mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47: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)
|
self.setMeshData(mesh)
|
||||||
|
|
||||||
|
def getWatchedNode(self):
|
||||||
|
return self._node
|
||||||
|
|
||||||
def render(self, renderer):
|
def render(self, renderer):
|
||||||
if not self._material:
|
if not self._material:
|
||||||
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag"))
|
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!
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
# source: Cura.proto
|
# source: Cura.proto
|
||||||
|
|
||||||
|
@ -21,7 +18,7 @@ _sym_db = _symbol_database.Default()
|
||||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
name='Cura.proto',
|
name='Cura.proto',
|
||||||
package='Cura',
|
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)
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
@ -57,11 +54,19 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor(
|
||||||
name='SkirtType', index=5, number=5,
|
name='SkirtType', index=5, number=5,
|
||||||
options=None,
|
options=None,
|
||||||
type=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,
|
containing_type=None,
|
||||||
options=None,
|
options=None,
|
||||||
serialized_start=430,
|
serialized_start=486,
|
||||||
serialized_end=528,
|
serialized_end=623,
|
||||||
)
|
)
|
||||||
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
|
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
|
||||||
|
|
||||||
|
@ -266,8 +271,22 @@ _LAYER = _descriptor.Descriptor(
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
options=None),
|
options=None),
|
||||||
_descriptor.FieldDescriptor(
|
_descriptor.FieldDescriptor(
|
||||||
name='polygons', full_name='Cura.Layer.polygons', index=1,
|
name='height', full_name='Cura.Layer.height', index=1,
|
||||||
number=2, type=11, cpp_type=10, label=3,
|
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=[],
|
has_default_value=False, default_value=[],
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
|
@ -284,7 +303,7 @@ _LAYER = _descriptor.Descriptor(
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=314,
|
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,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
options=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=[
|
extensions=[
|
||||||
],
|
],
|
||||||
|
@ -321,8 +347,8 @@ _POLYGON = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=369,
|
serialized_start=404,
|
||||||
serialized_end=528,
|
serialized_end=623,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -358,8 +384,8 @@ _GCODELAYER = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=530,
|
serialized_start=625,
|
||||||
serialized_end=568,
|
serialized_end=663,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -402,8 +428,8 @@ _OBJECTPRINTTIME = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=570,
|
serialized_start=665,
|
||||||
serialized_end=638,
|
serialized_end=733,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,8 +458,8 @@ _SETTINGLIST = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=640,
|
serialized_start=735,
|
||||||
serialized_end=686,
|
serialized_end=781,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -469,8 +495,8 @@ _SETTING = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=688,
|
serialized_start=783,
|
||||||
serialized_end=726,
|
serialized_end=821,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -499,8 +525,8 @@ _GCODEPREFIX = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=728,
|
serialized_start=823,
|
||||||
serialized_end=755,
|
serialized_end=850,
|
||||||
)
|
)
|
||||||
|
|
||||||
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT
|
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
from UM.Mesh.MeshData import MeshData
|
from UM.Mesh.MeshData import MeshData
|
||||||
|
from UM.Mesh.MeshBuilder import MeshBuilder
|
||||||
from UM.Math.Color import Color
|
from UM.Math.Color import Color
|
||||||
|
from UM.Math.Vector import Vector
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import math
|
import math
|
||||||
|
@ -13,12 +15,19 @@ class LayerData(MeshData):
|
||||||
self._layers = {}
|
self._layers = {}
|
||||||
self._element_counts = {}
|
self._element_counts = {}
|
||||||
|
|
||||||
def addPolygon(self, layer, type, data):
|
def addLayer(self, layer):
|
||||||
if layer not in self._layers:
|
if layer not in self._layers:
|
||||||
self._layers[layer] = []
|
self._layers[layer] = Layer(layer)
|
||||||
|
|
||||||
p = Polygon(self, type, data)
|
def addPolygon(self, layer, type, data, line_width):
|
||||||
self._layers[layer].append(p)
|
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):
|
def getLayers(self):
|
||||||
return self._layers
|
return self._layers
|
||||||
|
@ -26,14 +35,112 @@ class LayerData(MeshData):
|
||||||
def getElementCounts(self):
|
def getElementCounts(self):
|
||||||
return self._element_counts
|
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):
|
def build(self):
|
||||||
for layer, data in self._layers.items():
|
for layer, data in self._layers.items():
|
||||||
if layer not in self._element_counts:
|
data.build()
|
||||||
self._element_counts[layer] = []
|
|
||||||
|
|
||||||
for polygon in data:
|
self._element_counts[layer] = data.elementCount
|
||||||
polygon.build()
|
|
||||||
self._element_counts[layer].append(polygon.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():
|
class Polygon():
|
||||||
NoneType = 0
|
NoneType = 0
|
||||||
|
@ -42,34 +149,26 @@ class Polygon():
|
||||||
SkinType = 3
|
SkinType = 3
|
||||||
SupportType = 4
|
SupportType = 4
|
||||||
SkirtType = 5
|
SkirtType = 5
|
||||||
|
InfillType = 6
|
||||||
|
SupportInfillType = 7
|
||||||
|
|
||||||
def __init__(self, mesh, type, data):
|
def __init__(self, mesh, type, data, line_width):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._mesh = mesh
|
self._mesh = mesh
|
||||||
self._type = type
|
self._type = type
|
||||||
self._data = data
|
self._data = data
|
||||||
|
self._line_width = line_width / 1000
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self._begin = self._mesh._vertex_count
|
self._begin = self._mesh._vertex_count
|
||||||
self._mesh.addVertices(self._data)
|
self._mesh.addVertices(self._data)
|
||||||
self._end = self._begin + len(self._data) - 1
|
self._end = self._begin + len(self._data) - 1
|
||||||
|
|
||||||
color = None
|
color = self.getColor()
|
||||||
if self._type == self.Inset0Type:
|
color[3] = 2.0
|
||||||
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]
|
|
||||||
|
|
||||||
colors = [color for i in range(len(self._data))]
|
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 = []
|
indices = []
|
||||||
for i in range(self._begin, self._end):
|
for i in range(self._begin, self._end):
|
||||||
|
@ -80,6 +179,24 @@ class Polygon():
|
||||||
indices.append(self._begin)
|
indices.append(self._begin)
|
||||||
self._mesh.addIndices(numpy.array(indices, dtype=numpy.int32))
|
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
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
return self._type
|
return self._type
|
||||||
|
@ -90,4 +207,8 @@ class Polygon():
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def elementCount(self):
|
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()
|
settings = Application.getInstance().getActiveMachine()
|
||||||
layerHeight = settings.getSettingValueByKey("layer_height")
|
layerHeight = settings.getSettingValueByKey("layer_height")
|
||||||
|
|
||||||
|
mesh = MeshData()
|
||||||
for object in self._message.objects:
|
for object in self._message.objects:
|
||||||
try:
|
try:
|
||||||
node = objectIdMap[object.id]
|
node = objectIdMap[object.id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mesh = MeshData()
|
|
||||||
|
|
||||||
layerData = LayerData.LayerData()
|
layerData = LayerData.LayerData()
|
||||||
for layer in object.layers:
|
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:
|
for polygon in layer.polygons:
|
||||||
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array
|
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 = 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 = numpy.asarray(points, dtype=numpy.float32)
|
||||||
points /= 1000
|
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
|
points[:,2] *= -1
|
||||||
|
|
||||||
|
@ -55,16 +57,11 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
|
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
|
||||||
points -= numpy.array(center)
|
points -= numpy.array(center)
|
||||||
|
|
||||||
#points = numpy.pad(points, ((0,0), (0,1)), "constant", constant_values=(0.0, 1.0))
|
layerData.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
||||||
#inverse = node.getWorldTransformation().getInverse().getData()
|
|
||||||
#points = points.dot(inverse)
|
|
||||||
#points = points[:,0:3]
|
|
||||||
|
|
||||||
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.setMeshData(mesh)
|
||||||
new_node.setParent(self._scene.getRoot())
|
new_node.setParent(self._scene.getRoot())
|
||||||
|
|
|
@ -9,6 +9,10 @@ from UM.Event import Event, KeyEvent
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
from UM.Math.Color import Color
|
from UM.Math.Color import Color
|
||||||
|
from UM.Mesh.MeshData import MeshData
|
||||||
|
|
||||||
|
from cura.ConvexHullNode import ConvexHullNode
|
||||||
|
|
||||||
from . import LayerViewProxy
|
from . import LayerViewProxy
|
||||||
|
|
||||||
## View used to display g-code paths.
|
## View used to display g-code paths.
|
||||||
|
@ -22,6 +26,9 @@ class LayerView(View):
|
||||||
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
|
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
|
||||||
self._max_layers = 10
|
self._max_layers = 10
|
||||||
self._current_layer_num = 10
|
self._current_layer_num = 10
|
||||||
|
self._current_layer_mesh = None
|
||||||
|
|
||||||
|
self._solid_layers = 5
|
||||||
|
|
||||||
def getCurrentLayer(self):
|
def getCurrentLayer(self):
|
||||||
return self._current_layer_num
|
return self._current_layer_num
|
||||||
|
@ -45,6 +52,11 @@ class LayerView(View):
|
||||||
self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128))
|
self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128))
|
||||||
|
|
||||||
for node in DepthFirstIterator(scene.getRoot()):
|
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 not node.render(renderer):
|
||||||
if node.getMeshData() and node.isVisible():
|
if node.getMeshData() and node.isVisible():
|
||||||
if Selection.isSelected(node):
|
if Selection.isSelected(node):
|
||||||
|
@ -55,19 +67,39 @@ class LayerView(View):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
start = 0
|
# Render all layers below a certain number as line mesh instead of vertices.
|
||||||
end = 0
|
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()
|
# This uses glDrawRangeElements internally to only draw a certain range of lines.
|
||||||
for layer, counts in element_counts.items():
|
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
|
||||||
end += sum(counts)
|
|
||||||
## Hack to ensure the end is correct. Not quite sure what causes this
|
|
||||||
end += 2 * len(counts)
|
|
||||||
|
|
||||||
if layer >= self._current_layer_num:
|
# We currently recreate the current "solid" layers every time a
|
||||||
break
|
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):
|
def setLayer(self, value):
|
||||||
if self._current_layer_num != value:
|
if self._current_layer_num != value:
|
||||||
|
@ -76,6 +108,8 @@ class LayerView(View):
|
||||||
self._current_layer_num = 0
|
self._current_layer_num = 0
|
||||||
if self._current_layer_num > self._max_layers:
|
if self._current_layer_num > self._max_layers:
|
||||||
self._current_layer_num = self._max_layers
|
self._current_layer_num = self._max_layers
|
||||||
|
|
||||||
|
self._current_layer_mesh = None
|
||||||
self.currentLayerNumChanged.emit()
|
self.currentLayerNumChanged.emit()
|
||||||
|
|
||||||
currentLayerNumChanged = Signal()
|
currentLayerNumChanged = Signal()
|
||||||
|
@ -96,7 +130,7 @@ class LayerView(View):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
continue
|
continue
|
||||||
if new_max_layers < len(layer_data.getLayers()):
|
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:
|
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
|
||||||
self._max_layers = new_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 {
|
ButtonStyle {
|
||||||
background: UM.AngledCornerRectangle {
|
background: Item {
|
||||||
implicitWidth: UM.Theme.sizes.button.width;
|
implicitWidth: UM.Theme.sizes.button.width;
|
||||||
implicitHeight: UM.Theme.sizes.button.height;
|
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 {
|
Rectangle {
|
||||||
anchors.bottom: parent.top;
|
anchors.bottom: parent.verticalCenter;
|
||||||
|
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
height: control.hovered ? label.height : 0;
|
height: control.hovered ? parent.height / 2 + label.height : 0;
|
||||||
Behavior on height { NumberAnimation { duration: 75; } }
|
Behavior on height { NumberAnimation { duration: 100; } }
|
||||||
|
|
||||||
opacity: control.hovered ? 1.0 : 0.0;
|
opacity: control.hovered ? 1.0 : 0.0;
|
||||||
Behavior on opacity { NumberAnimation { duration: 75; } }
|
Behavior on opacity { NumberAnimation { duration: 100; } }
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: label
|
id: label;
|
||||||
anchors.horizontalCenter: parent.horizontalCenter;
|
anchors.horizontalCenter: parent.horizontalCenter;
|
||||||
text: control.text;
|
text: control.text.replace("&", "");
|
||||||
font: UM.Theme.fonts.button_tooltip;
|
font: UM.Theme.fonts.button_tooltip;
|
||||||
color: UM.Theme.colors.button_tooltip_text;
|
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 {
|
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 {
|
property Component sidebar_category: Component {
|
||||||
ButtonStyle {
|
ButtonStyle {
|
||||||
background: UM.AngledCornerRectangle {
|
background: UM.AngledCornerRectangle {
|
||||||
|
|
|
@ -88,6 +88,9 @@
|
||||||
"setting_validation_warning": [255, 186, 15, 255],
|
"setting_validation_warning": [255, 186, 15, 255],
|
||||||
"setting_validation_ok": [255, 255, 255, 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": [245, 245, 245, 255],
|
||||||
"slider_groove_border": [205, 202, 201, 255],
|
"slider_groove_border": [205, 202, 201, 255],
|
||||||
"slider_groove_fill": [205, 202, 201, 255],
|
"slider_groove_fill": [205, 202, 201, 255],
|
||||||
|
@ -135,6 +138,10 @@
|
||||||
"button": [4.25, 4.25],
|
"button": [4.25, 4.25],
|
||||||
"button_icon": [2.9, 2.9],
|
"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],
|
"scrollbar": [0.5, 0.5],
|
||||||
|
|
||||||
"slider_groove": [0.5, 0.5],
|
"slider_groove": [0.5, 0.5],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue