mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 14:37:29 -06:00
Merge branch '15.06'
* 15.06: Implement rendering the top 5 layers solid and with infill Add a createMesh function to LayerData::Layer that creates a mesh from a layer Add support for line width and infill types to LayerData::Polygon Use the new layer message properties to properly create layers Do not render the convex hull node unless the object is selected Update generated protobuf protocol file as per CuraEngine changes helps with making the messagestack adapt to the total size of messages + pogressbar Defines the style of the progressbar Makes the openfile button blue/active as long as there is no file loaded.
This commit is contained in:
commit
46576ba5e7
7 changed files with 322 additions and 88 deletions
|
@ -48,6 +48,9 @@ class ConvexHullNode(SceneNode):
|
|||
|
||||
self.setMeshData(mesh)
|
||||
|
||||
def getWatchedNode(self):
|
||||
return self._node
|
||||
|
||||
def render(self, renderer):
|
||||
if not self._material:
|
||||
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag"))
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: Cura.proto
|
||||
|
||||
|
@ -21,7 +18,7 @@ _sym_db = _symbol_database.Default()
|
|||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='Cura.proto',
|
||||
package='Cura',
|
||||
serialized_pb=_b('\n\nCura.proto\x12\x04\x43ura\"+\n\nObjectList\x12\x1d\n\x07objects\x18\x01 \x03(\x0b\x32\x0c.Cura.Object\"i\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12\x1f\n\x08settings\x18\x05 \x03(\x0b\x32\r.Cura.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"7\n\x10SlicedObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.Cura.SlicedObject\"7\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x1b\n\x06layers\x18\x02 \x03(\x0b\x32\x0b.Cura.Layer\"4\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x1f\n\x08polygons\x18\x02 \x03(\x0b\x32\r.Cura.Polygon\"\x9f\x01\n\x07Polygon\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.Cura.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\"b\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\".\n\x0bSettingList\x12\x1f\n\x08settings\x18\x01 \x03(\x0b\x32\r.Cura.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3')
|
||||
serialized_pb=_b('\n\nCura.proto\x12\x04\x43ura\"+\n\nObjectList\x12\x1d\n\x07objects\x18\x01 \x03(\x0b\x32\x0c.Cura.Object\"i\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12\x1f\n\x08settings\x18\x05 \x03(\x0b\x32\r.Cura.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"7\n\x10SlicedObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.Cura.SlicedObject\"7\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x1b\n\x06layers\x18\x02 \x03(\x0b\x32\x0b.Cura.Layer\"W\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x02\x12\x11\n\tthickness\x18\x03 \x01(\x02\x12\x1f\n\x08polygons\x18\x04 \x03(\x0b\x32\r.Cura.Polygon\"\xdb\x01\n\x07Polygon\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.Cura.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\x12\x12\n\nline_width\x18\x03 \x01(\x02\"\x89\x01\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\x12\x0e\n\nInfillType\x10\x06\x12\x15\n\x11SupportInfillType\x10\x07\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\".\n\x0bSettingList\x12\x1f\n\x08settings\x18\x01 \x03(\x0b\x32\r.Cura.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3')
|
||||
)
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
|
@ -57,11 +54,19 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor(
|
|||
name='SkirtType', index=5, number=5,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='InfillType', index=6, number=6,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SupportInfillType', index=7, number=7,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=430,
|
||||
serialized_end=528,
|
||||
serialized_start=486,
|
||||
serialized_end=623,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
|
||||
|
||||
|
@ -266,8 +271,22 @@ _LAYER = _descriptor.Descriptor(
|
|||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='polygons', full_name='Cura.Layer.polygons', index=1,
|
||||
number=2, type=11, cpp_type=10, label=3,
|
||||
name='height', full_name='Cura.Layer.height', index=1,
|
||||
number=2, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='thickness', full_name='Cura.Layer.thickness', index=2,
|
||||
number=3, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='polygons', full_name='Cura.Layer.polygons', index=3,
|
||||
number=4, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
|
@ -284,7 +303,7 @@ _LAYER = _descriptor.Descriptor(
|
|||
oneofs=[
|
||||
],
|
||||
serialized_start=314,
|
||||
serialized_end=366,
|
||||
serialized_end=401,
|
||||
)
|
||||
|
||||
|
||||
|
@ -309,6 +328,13 @@ _POLYGON = _descriptor.Descriptor(
|
|||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='line_width', full_name='Cura.Polygon.line_width', index=2,
|
||||
number=3, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
|
@ -321,8 +347,8 @@ _POLYGON = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=369,
|
||||
serialized_end=528,
|
||||
serialized_start=404,
|
||||
serialized_end=623,
|
||||
)
|
||||
|
||||
|
||||
|
@ -358,8 +384,8 @@ _GCODELAYER = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=530,
|
||||
serialized_end=568,
|
||||
serialized_start=625,
|
||||
serialized_end=663,
|
||||
)
|
||||
|
||||
|
||||
|
@ -402,8 +428,8 @@ _OBJECTPRINTTIME = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=570,
|
||||
serialized_end=638,
|
||||
serialized_start=665,
|
||||
serialized_end=733,
|
||||
)
|
||||
|
||||
|
||||
|
@ -432,8 +458,8 @@ _SETTINGLIST = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=640,
|
||||
serialized_end=686,
|
||||
serialized_start=735,
|
||||
serialized_end=781,
|
||||
)
|
||||
|
||||
|
||||
|
@ -469,8 +495,8 @@ _SETTING = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=688,
|
||||
serialized_end=726,
|
||||
serialized_start=783,
|
||||
serialized_end=821,
|
||||
)
|
||||
|
||||
|
||||
|
@ -499,8 +525,8 @@ _GCODEPREFIX = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=728,
|
||||
serialized_end=755,
|
||||
serialized_start=823,
|
||||
serialized_end=850,
|
||||
)
|
||||
|
||||
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||
from UM.Math.Color import Color
|
||||
from UM.Math.Vector import Vector
|
||||
|
||||
import numpy
|
||||
import math
|
||||
|
@ -13,12 +15,19 @@ class LayerData(MeshData):
|
|||
self._layers = {}
|
||||
self._element_counts = {}
|
||||
|
||||
def addPolygon(self, layer, type, data):
|
||||
def addLayer(self, layer):
|
||||
if layer not in self._layers:
|
||||
self._layers[layer] = []
|
||||
self._layers[layer] = Layer(layer)
|
||||
|
||||
p = Polygon(self, type, data)
|
||||
self._layers[layer].append(p)
|
||||
def addPolygon(self, layer, type, data, line_width):
|
||||
if layer not in self._layers:
|
||||
self.addLayer(layer)
|
||||
|
||||
p = Polygon(self, type, data, line_width)
|
||||
self._layers[layer].polygons.append(p)
|
||||
|
||||
def getLayer(self, layer):
|
||||
return self._layers[layer]
|
||||
|
||||
def getLayers(self):
|
||||
return self._layers
|
||||
|
@ -26,14 +35,112 @@ class LayerData(MeshData):
|
|||
def getElementCounts(self):
|
||||
return self._element_counts
|
||||
|
||||
def setLayerHeight(self, layer, height):
|
||||
if layer not in self._layers:
|
||||
self.addLayer(layer)
|
||||
|
||||
self._layers[layer].setHeight(height)
|
||||
|
||||
def setLayerThickness(self, layer, thickness):
|
||||
if layer not in self._layers:
|
||||
self.addLayer(layer)
|
||||
|
||||
self._layers[layer].setThickness(thickness)
|
||||
|
||||
def build(self):
|
||||
for layer, data in self._layers.items():
|
||||
if layer not in self._element_counts:
|
||||
self._element_counts[layer] = []
|
||||
data.build()
|
||||
|
||||
for polygon in data:
|
||||
polygon.build()
|
||||
self._element_counts[layer].append(polygon.elementCount)
|
||||
self._element_counts[layer] = data.elementCount
|
||||
|
||||
class Layer():
|
||||
def __init__(self, id):
|
||||
self._id = id
|
||||
self._height = 0.0
|
||||
self._thickness = 0.0
|
||||
self._polygons = []
|
||||
self._element_count = 0
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self._height
|
||||
|
||||
@property
|
||||
def thickness(self):
|
||||
return self._thickness
|
||||
|
||||
@property
|
||||
def polygons(self):
|
||||
return self._polygons
|
||||
|
||||
@property
|
||||
def elementCount(self):
|
||||
return self._element_count
|
||||
|
||||
def setHeight(self, height):
|
||||
self._height = height
|
||||
|
||||
def setThickness(self, thickness):
|
||||
self._thickness = thickness
|
||||
|
||||
def build(self):
|
||||
for polygon in self._polygons:
|
||||
if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType:
|
||||
continue
|
||||
|
||||
polygon.build()
|
||||
self._element_count += polygon.elementCount
|
||||
|
||||
def createMesh(self):
|
||||
builder = MeshBuilder()
|
||||
|
||||
for polygon in self._polygons:
|
||||
poly_color = polygon.getColor()
|
||||
poly_color = Color(poly_color[0], poly_color[1], poly_color[2], poly_color[3])
|
||||
|
||||
points = numpy.copy(polygon.data)
|
||||
if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
|
||||
points[:,1] -= 0.01
|
||||
|
||||
# Calculate normals for the entire polygon using numpy.
|
||||
normals = numpy.copy(points)
|
||||
normals[:,1] = 0.0 # We are only interested in 2D normals
|
||||
|
||||
# Calculate the edges between points.
|
||||
# The call to numpy.roll shifts the entire array by one so that
|
||||
# we end up subtracting each next point from the current, wrapping
|
||||
# around. This gives us the edges from the next point to the current
|
||||
# point.
|
||||
normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0)
|
||||
# Calculate the length of each edge using standard Pythagoras
|
||||
lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2)
|
||||
# The normal of a 2D vector is equal to its x and y coordinates swapped
|
||||
# and then x inverted. This code does that.
|
||||
normals[:,[0, 2]] = normals[:,[2, 0]]
|
||||
normals[:,0] *= -1
|
||||
|
||||
# Normalize the normals.
|
||||
normals[:,0] /= lengths
|
||||
normals[:,2] /= lengths
|
||||
|
||||
# Scale all by the line width of the polygon so we can easily offset.
|
||||
normals *= (polygon.lineWidth / 2)
|
||||
|
||||
#TODO: Use numpy magic to perform the vertex creation to speed up things.
|
||||
for i in range(len(points)):
|
||||
start = points[i - 1]
|
||||
end = points[i]
|
||||
|
||||
normal = normals[i - 1]
|
||||
|
||||
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.getData()
|
||||
|
||||
class Polygon():
|
||||
NoneType = 0
|
||||
|
@ -42,34 +149,26 @@ class Polygon():
|
|||
SkinType = 3
|
||||
SupportType = 4
|
||||
SkirtType = 5
|
||||
InfillType = 6
|
||||
SupportInfillType = 7
|
||||
|
||||
def __init__(self, mesh, type, data):
|
||||
def __init__(self, mesh, type, data, line_width):
|
||||
super().__init__()
|
||||
self._mesh = mesh
|
||||
self._type = type
|
||||
self._data = data
|
||||
self._line_width = line_width / 1000
|
||||
|
||||
def build(self):
|
||||
self._begin = self._mesh._vertex_count
|
||||
self._mesh.addVertices(self._data)
|
||||
self._end = self._begin + len(self._data) - 1
|
||||
|
||||
color = None
|
||||
if self._type == self.Inset0Type:
|
||||
color = [1, 0, 0, 1]
|
||||
elif self._type == self.InsetXType:
|
||||
color = [0, 1, 0, 1]
|
||||
elif self._type == self.SkinType:
|
||||
color = [1, 1, 0, 1]
|
||||
elif self._type == self.SupportType:
|
||||
color = [0, 1, 1, 1]
|
||||
elif self._type == self.SkirtType:
|
||||
color = [0, 1, 1, 1]
|
||||
else:
|
||||
color = [1, 1, 1, 1]
|
||||
color = self.getColor()
|
||||
color[3] = 2.0
|
||||
|
||||
colors = [color for i in range(len(self._data))]
|
||||
self._mesh.addColors(numpy.array(colors, dtype=numpy.float32))
|
||||
self._mesh.addColors(numpy.array(colors, dtype=numpy.float32) * 0.5)
|
||||
|
||||
indices = []
|
||||
for i in range(self._begin, self._end):
|
||||
|
@ -80,6 +179,24 @@ class Polygon():
|
|||
indices.append(self._begin)
|
||||
self._mesh.addIndices(numpy.array(indices, dtype=numpy.int32))
|
||||
|
||||
def getColor(self):
|
||||
if self._type == self.Inset0Type:
|
||||
return [1.0, 0.0, 0.0, 1.0]
|
||||
elif self._type == self.InsetXType:
|
||||
return [0.0, 1.0, 0.0, 1.0]
|
||||
elif self._type == self.SkinType:
|
||||
return [1.0, 1.0, 0.0, 1.0]
|
||||
elif self._type == self.SupportType:
|
||||
return [0.0, 1.0, 1.0, 1.0]
|
||||
elif self._type == self.SkirtType:
|
||||
return [0.0, 1.0, 1.0, 1.0]
|
||||
elif self._type == self.InfillType:
|
||||
return [1.0, 1.0, 0.0, 1.0]
|
||||
elif self._type == self.SupportInfillType:
|
||||
return [0.0, 1.0, 1.0, 1.0]
|
||||
else:
|
||||
return [1.0, 1.0, 1.0, 1.0]
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
@ -90,4 +207,8 @@ class Polygon():
|
|||
|
||||
@property
|
||||
def elementCount(self):
|
||||
return (self._end - self._begin) * 2 #The range of vertices multiplied by 2 since each vertex is used twice
|
||||
return ((self._end - self._begin) + 1) * 2 #The range of vertices multiplied by 2 since each vertex is used twice
|
||||
|
||||
@property
|
||||
def lineWidth(self):
|
||||
return self._line_width
|
||||
|
|
|
@ -32,22 +32,24 @@ class ProcessSlicedObjectListJob(Job):
|
|||
settings = Application.getInstance().getActiveMachine()
|
||||
layerHeight = settings.getSettingValueByKey("layer_height")
|
||||
|
||||
mesh = MeshData()
|
||||
for object in self._message.objects:
|
||||
try:
|
||||
try:
|
||||
node = objectIdMap[object.id]
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
mesh = MeshData()
|
||||
|
||||
layerData = LayerData.LayerData()
|
||||
for layer in object.layers:
|
||||
layerData.addLayer(layer.id)
|
||||
layerData.setLayerHeight(layer.id, layer.height)
|
||||
layerData.setLayerThickness(layer.id, layer.thickness)
|
||||
for polygon in layer.polygons:
|
||||
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array
|
||||
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
||||
points = numpy.asarray(points, dtype=numpy.float32)
|
||||
points /= 1000
|
||||
points = numpy.insert(points, 1, layer.id * layerHeight, axis = 1)
|
||||
points = numpy.insert(points, 1, (layer.height / 1000), axis = 1)
|
||||
|
||||
points[:,2] *= -1
|
||||
|
||||
|
@ -55,16 +57,11 @@ class ProcessSlicedObjectListJob(Job):
|
|||
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
|
||||
points -= numpy.array(center)
|
||||
|
||||
#points = numpy.pad(points, ((0,0), (0,1)), "constant", constant_values=(0.0, 1.0))
|
||||
#inverse = node.getWorldTransformation().getInverse().getData()
|
||||
#points = points.dot(inverse)
|
||||
#points = points[:,0:3]
|
||||
layerData.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
||||
|
||||
layerData.addPolygon(layer.id, polygon.type, points)
|
||||
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
||||
layerData.build()
|
||||
mesh.layerData = layerData
|
||||
|
||||
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
||||
layerData.build()
|
||||
mesh.layerData = layerData
|
||||
|
||||
new_node.setMeshData(mesh)
|
||||
new_node.setParent(self._scene.getRoot())
|
||||
|
|
|
@ -9,6 +9,10 @@ from UM.Event import Event, KeyEvent
|
|||
from UM.Signal import Signal
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Math.Color import Color
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
|
||||
from cura.ConvexHullNode import ConvexHullNode
|
||||
|
||||
from . import LayerViewProxy
|
||||
|
||||
## View used to display g-code paths.
|
||||
|
@ -22,6 +26,9 @@ class LayerView(View):
|
|||
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
|
||||
self._max_layers = 10
|
||||
self._current_layer_num = 10
|
||||
self._current_layer_mesh = None
|
||||
|
||||
self._solid_layers = 5
|
||||
|
||||
def getCurrentLayer(self):
|
||||
return self._current_layer_num
|
||||
|
@ -45,6 +52,11 @@ class LayerView(View):
|
|||
self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128))
|
||||
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
# We do not want to render ConvexHullNode as it conflicts with the bottom layers.
|
||||
# However, it is somewhat relevant when the node is selected, so do render it then.
|
||||
if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()):
|
||||
continue
|
||||
|
||||
if not node.render(renderer):
|
||||
if node.getMeshData() and node.isVisible():
|
||||
if Selection.isSelected(node):
|
||||
|
@ -55,19 +67,39 @@ class LayerView(View):
|
|||
except AttributeError:
|
||||
continue
|
||||
|
||||
start = 0
|
||||
end = 0
|
||||
# Render all layers below a certain number as line mesh instead of vertices.
|
||||
if self._current_layer_num - self._solid_layers > -1:
|
||||
start = 0
|
||||
end = 0
|
||||
element_counts = layer_data.getElementCounts()
|
||||
for layer, counts in element_counts.items():
|
||||
if layer + self._solid_layers > self._current_layer_num:
|
||||
break
|
||||
end += counts
|
||||
|
||||
element_counts = layer_data.getElementCounts()
|
||||
for layer, counts in element_counts.items():
|
||||
end += sum(counts)
|
||||
## Hack to ensure the end is correct. Not quite sure what causes this
|
||||
end += 2 * len(counts)
|
||||
# This uses glDrawRangeElements internally to only draw a certain range of lines.
|
||||
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
|
||||
|
||||
if layer >= self._current_layer_num:
|
||||
break
|
||||
# We currently recreate the current "solid" layers every time a
|
||||
if not self._current_layer_mesh:
|
||||
self._current_layer_mesh = MeshData()
|
||||
for i in range(self._solid_layers):
|
||||
layer = self._current_layer_num - i
|
||||
if layer < 0:
|
||||
continue
|
||||
|
||||
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
|
||||
layer_mesh = layer_data.getLayer(layer).createMesh()
|
||||
if not layer_mesh or layer_mesh.getVertices() is None:
|
||||
continue
|
||||
|
||||
self._current_layer_mesh.addVertices(layer_mesh.getVertices())
|
||||
|
||||
# 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.
|
||||
brightness = (2.0 - (i / self._solid_layers)) / 2.0
|
||||
self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness)
|
||||
|
||||
renderer.queueNode(node, mesh = self._current_layer_mesh, material = self._material)
|
||||
|
||||
def setLayer(self, value):
|
||||
if self._current_layer_num != value:
|
||||
|
@ -76,6 +108,8 @@ class LayerView(View):
|
|||
self._current_layer_num = 0
|
||||
if self._current_layer_num > self._max_layers:
|
||||
self._current_layer_num = self._max_layers
|
||||
|
||||
self._current_layer_mesh = None
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
currentLayerNumChanged = Signal()
|
||||
|
@ -96,7 +130,7 @@ class LayerView(View):
|
|||
except AttributeError:
|
||||
continue
|
||||
if new_max_layers < len(layer_data.getLayers()):
|
||||
new_max_layers = len(layer_data.getLayers())
|
||||
new_max_layers = len(layer_data.getLayers()) - 1
|
||||
|
||||
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
|
||||
self._max_layers = new_max_layers
|
||||
|
|
|
@ -35,39 +35,42 @@ QtObject {
|
|||
}
|
||||
}
|
||||
|
||||
property Component open_file_button: Component {
|
||||
property Component open_file_button: Component {
|
||||
ButtonStyle {
|
||||
background: UM.AngledCornerRectangle {
|
||||
background: Item {
|
||||
implicitWidth: UM.Theme.sizes.button.width;
|
||||
implicitHeight: UM.Theme.sizes.button.height;
|
||||
color: {
|
||||
if(control.hovered) {
|
||||
return UM.Theme.colors.button_active_hover;
|
||||
} else {
|
||||
return UM.Theme.colors.button_active;
|
||||
}
|
||||
}
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
cornerSize: UM.Theme.sizes.default_margin.width;
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.top;
|
||||
|
||||
anchors.bottom: parent.verticalCenter;
|
||||
width: parent.width;
|
||||
height: control.hovered ? label.height : 0;
|
||||
Behavior on height { NumberAnimation { duration: 75; } }
|
||||
height: control.hovered ? parent.height / 2 + label.height : 0;
|
||||
Behavior on height { NumberAnimation { duration: 100; } }
|
||||
|
||||
opacity: control.hovered ? 1.0 : 0.0;
|
||||
Behavior on opacity { NumberAnimation { duration: 75; } }
|
||||
Behavior on opacity { NumberAnimation { duration: 100; } }
|
||||
|
||||
Label {
|
||||
id: label
|
||||
id: label;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
text: control.text;
|
||||
text: control.text.replace("&", "");
|
||||
font: UM.Theme.fonts.button_tooltip;
|
||||
color: UM.Theme.colors.button_tooltip_text;
|
||||
}
|
||||
}
|
||||
|
||||
UM.AngledCornerRectangle {
|
||||
anchors.fill: parent;
|
||||
color: {
|
||||
if(control.hovered) {
|
||||
return UM.Theme.colors.button_active_hover;
|
||||
} else {
|
||||
return UM.Theme.colors.button_active;
|
||||
}
|
||||
}
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
cornerSize: UM.Theme.sizes.default_margin.width;
|
||||
}
|
||||
}
|
||||
|
||||
label: Item {
|
||||
|
@ -148,6 +151,49 @@ QtObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
property Component progressbar: Component{
|
||||
ProgressBarStyle {
|
||||
background: UM.AngledCornerRectangle {
|
||||
anchors.fill: parent
|
||||
anchors.left: parent.left
|
||||
implicitWidth: UM.Theme.sizes.progressbar.width
|
||||
implicitHeight: UM.Theme.sizes.progressbar.height
|
||||
color: "transparent"
|
||||
}
|
||||
progress: UM.AngledCornerRectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.fill: parent
|
||||
cornerSize: UM.Theme.sizes.progressbar_control.height
|
||||
color: UM.Theme.colors.progressbar_background
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: UM.Theme.sizes.progressbar_margin.width
|
||||
visible: control.indeterminate
|
||||
Row {
|
||||
Repeater {
|
||||
UM.AngledCornerRectangle {
|
||||
cornerSize: UM.Theme.sizes.progressbar_control.height
|
||||
color: UM.Theme.colors.progressbar_control
|
||||
width: UM.Theme.sizes.progressbar_control.width
|
||||
height: UM.Theme.sizes.progressbar_control.height
|
||||
}
|
||||
model: 1
|
||||
}
|
||||
SequentialAnimation on x {
|
||||
id: xAnim
|
||||
property int animEndPoint: UM.Theme.sizes.progressbar.width - UM.Theme.sizes.progressbar_control.width
|
||||
running: control.indeterminate
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { from: 0; to: xAnim.animEndPoint; duration: 2000;}
|
||||
NumberAnimation { from: xAnim.animEndPoint; to: 0; duration: 2000;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property Component sidebar_category: Component {
|
||||
ButtonStyle {
|
||||
background: UM.AngledCornerRectangle {
|
||||
|
|
|
@ -88,6 +88,9 @@
|
|||
"setting_validation_warning": [255, 186, 15, 255],
|
||||
"setting_validation_ok": [255, 255, 255, 255],
|
||||
|
||||
"progressbar_background": [245, 245, 245, 255],
|
||||
"progressbar_control": [12, 169, 227, 255],
|
||||
|
||||
"slider_groove": [245, 245, 245, 255],
|
||||
"slider_groove_border": [205, 202, 201, 255],
|
||||
"slider_groove_fill": [205, 202, 201, 255],
|
||||
|
@ -135,6 +138,10 @@
|
|||
"button": [4.25, 4.25],
|
||||
"button_icon": [2.9, 2.9],
|
||||
|
||||
"progressbar": [26.0, 0.5],
|
||||
"progressbar_control": [8.0, 0.5],
|
||||
"progressbar_padding": [0.0, 1.0],
|
||||
|
||||
"scrollbar": [0.5, 0.5],
|
||||
|
||||
"slider_groove": [0.5, 0.5],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue