mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-21 21:29:41 +08:00

* 15.10: (39 commits) Remove unused import in StartSliceJob conforming to code style fix typo's.. Adjust initial view to be slightly from the side uses a different method to check whether a machine name excists Sets the languageComboBox to the default language Remove per-group settings for now Make sure to send all settings when an object overrides the profile Properly emit writeStarted in RemovableDriveOutputDevice Add xy_offset setting to list of settings that trigger a disallowed area update Properly trigger a reslice when the active instance is changed Wizardpages without hack Only hides the window when there are no more pages Only add layer data node after all processing Also account for "xy_offset" setting for the disallowed areas JSON: workaround for stutter in spiralize vase: set travel speed to printing speed Adds a color for the error-messages Shows an error message when a user tries to add a printer with a name that already excists. JSON: support bottom stair step height defaults changed so that the bottom distance to the model isn't violated too much Try to use Protobuf CPP implementation if it is available ...
260 lines
8.2 KiB
Python
260 lines
8.2 KiB
Python
# Copyright (c) 2015 Ultimaker B.V.
|
|
# 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
|
|
import copy
|
|
|
|
class LayerData(MeshData):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._layers = {}
|
|
self._element_counts = {}
|
|
|
|
def addLayer(self, layer):
|
|
if layer not in self._layers:
|
|
self._layers[layer] = Layer(layer)
|
|
|
|
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):
|
|
if layer in self._layers:
|
|
return self._layers[layer]
|
|
|
|
def getLayers(self):
|
|
return self._layers
|
|
|
|
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):
|
|
vertex_count = 0
|
|
for layer, data in self._layers.items():
|
|
vertex_count += data.vertexCount()
|
|
|
|
vertices = numpy.empty((vertex_count, 3), numpy.float32)
|
|
colors = numpy.empty((vertex_count, 4), numpy.float32)
|
|
indices = numpy.empty((vertex_count, 2), numpy.int32)
|
|
|
|
offset = 0
|
|
for layer, data in self._layers.items():
|
|
offset = data.build(offset, vertices, colors, indices)
|
|
self._element_counts[layer] = data.elementCount
|
|
|
|
self.clear()
|
|
self.addVertices(vertices)
|
|
self.addColors(colors)
|
|
self.addIndices(indices.flatten())
|
|
|
|
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 vertexCount(self):
|
|
result = 0
|
|
for polygon in self._polygons:
|
|
result += polygon.vertexCount()
|
|
|
|
return result
|
|
|
|
def build(self, offset, vertices, colors, indices):
|
|
result = offset
|
|
for polygon in self._polygons:
|
|
if polygon.type == Polygon.InfillType or polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
|
|
continue
|
|
|
|
polygon.build(result, vertices, colors, indices)
|
|
result += polygon.vertexCount()
|
|
self._element_count += polygon.elementCount
|
|
|
|
return result
|
|
|
|
def createMesh(self):
|
|
return self.createMeshOrJumps(True)
|
|
|
|
def createJumps(self):
|
|
return self.createMeshOrJumps(False)
|
|
|
|
def createMeshOrJumps(self, make_mesh):
|
|
builder = MeshBuilder()
|
|
|
|
for polygon in self._polygons:
|
|
if make_mesh and (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
|
|
continue
|
|
if not make_mesh and not (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
|
|
continue
|
|
|
|
poly_color = polygon.getColor()
|
|
|
|
points = numpy.copy(polygon.data)
|
|
if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
|
|
points[:,1] -= 0.01
|
|
if polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
|
|
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
|
|
Inset0Type = 1
|
|
InsetXType = 2
|
|
SkinType = 3
|
|
SupportType = 4
|
|
SkirtType = 5
|
|
InfillType = 6
|
|
SupportInfillType = 7
|
|
MoveCombingType = 8
|
|
MoveRetractionType = 9
|
|
|
|
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, offset, vertices, colors, indices):
|
|
self._begin = offset
|
|
self._end = self._begin + len(self._data) - 1
|
|
|
|
color = self.getColor()
|
|
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
|
|
color = numpy.array([color.r, color.g, color.b, color.a], numpy.float32)
|
|
|
|
vertices[self._begin:self._end + 1, :] = self._data[:, :]
|
|
colors[self._begin:self._end + 1, :] = color
|
|
|
|
for i in range(self._begin, self._end):
|
|
indices[i, 0] = i
|
|
indices[i, 1] = i + 1
|
|
|
|
indices[self._end, 0] = self._end
|
|
indices[self._end, 1] = self._begin
|
|
|
|
def getColor(self):
|
|
if self._type == self.Inset0Type:
|
|
return Color(1.0, 0.0, 0.0, 1.0)
|
|
elif self._type == self.InsetXType:
|
|
return Color(0.0, 1.0, 0.0, 1.0)
|
|
elif self._type == self.SkinType:
|
|
return Color(1.0, 1.0, 0.0, 1.0)
|
|
elif self._type == self.SupportType:
|
|
return Color(0.0, 1.0, 1.0, 1.0)
|
|
elif self._type == self.SkirtType:
|
|
return Color(0.0, 1.0, 1.0, 1.0)
|
|
elif self._type == self.InfillType:
|
|
return Color(1.0, 0.74, 0.0, 1.0)
|
|
elif self._type == self.SupportInfillType:
|
|
return Color(0.0, 1.0, 1.0, 1.0)
|
|
elif self._type == self.MoveCombingType:
|
|
return Color(0.0, 0.0, 1.0, 1.0)
|
|
elif self._type == self.MoveRetractionType:
|
|
return Color(0.5, 0.5, 1.0, 1.0)
|
|
else:
|
|
return Color(1.0, 1.0, 1.0, 1.0)
|
|
|
|
def vertexCount(self):
|
|
return len(self._data)
|
|
|
|
@property
|
|
def type(self):
|
|
return self._type
|
|
|
|
@property
|
|
def data(self):
|
|
return self._data
|
|
|
|
@property
|
|
def elementCount(self):
|
|
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
|