LayerData.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. # Copyright (c) 2015 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from UM.Mesh.MeshData import MeshData
  4. from UM.Mesh.MeshBuilder import MeshBuilder
  5. from UM.Math.Color import Color
  6. from UM.Math.Vector import Vector
  7. import numpy
  8. import math
  9. import copy
  10. class LayerData(MeshData):
  11. def __init__(self):
  12. super().__init__()
  13. self._layers = {}
  14. self._element_counts = {}
  15. def addLayer(self, layer):
  16. if layer not in self._layers:
  17. self._layers[layer] = Layer(layer)
  18. def addPolygon(self, layer, type, data, line_width):
  19. if layer not in self._layers:
  20. self.addLayer(layer)
  21. p = Polygon(self, type, data, line_width)
  22. self._layers[layer].polygons.append(p)
  23. def getLayer(self, layer):
  24. if layer in self._layers:
  25. return self._layers[layer]
  26. def getLayers(self):
  27. return self._layers
  28. def getElementCounts(self):
  29. return self._element_counts
  30. def setLayerHeight(self, layer, height):
  31. if layer not in self._layers:
  32. self.addLayer(layer)
  33. self._layers[layer].setHeight(height)
  34. def setLayerThickness(self, layer, thickness):
  35. if layer not in self._layers:
  36. self.addLayer(layer)
  37. self._layers[layer].setThickness(thickness)
  38. def build(self):
  39. vertex_count = 0
  40. for layer, data in self._layers.items():
  41. vertex_count += data.vertexCount()
  42. vertices = numpy.empty((vertex_count, 3), numpy.float32)
  43. colors = numpy.empty((vertex_count, 4), numpy.float32)
  44. indices = numpy.empty((vertex_count, 2), numpy.int32)
  45. offset = 0
  46. for layer, data in self._layers.items():
  47. offset = data.build(offset, vertices, colors, indices)
  48. self._element_counts[layer] = data.elementCount
  49. self.addVertices(vertices)
  50. self.addColors(colors)
  51. self.addIndices(indices.flatten())
  52. class Layer():
  53. def __init__(self, id):
  54. self._id = id
  55. self._height = 0.0
  56. self._thickness = 0.0
  57. self._polygons = []
  58. self._element_count = 0
  59. @property
  60. def height(self):
  61. return self._height
  62. @property
  63. def thickness(self):
  64. return self._thickness
  65. @property
  66. def polygons(self):
  67. return self._polygons
  68. @property
  69. def elementCount(self):
  70. return self._element_count
  71. def setHeight(self, height):
  72. self._height = height
  73. def setThickness(self, thickness):
  74. self._thickness = thickness
  75. def vertexCount(self):
  76. result = 0
  77. for polygon in self._polygons:
  78. result += polygon.vertexCount()
  79. return result
  80. def build(self, offset, vertices, colors, indices):
  81. result = offset
  82. for polygon in self._polygons:
  83. if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType or polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
  84. continue
  85. polygon.build(result, vertices, colors, indices)
  86. result += polygon.vertexCount()
  87. self._element_count += polygon.elementCount
  88. return result
  89. def createMesh(self):
  90. return self.createMeshOrJumps(True)
  91. def createJumps(self):
  92. return self.createMeshOrJumps(False)
  93. def createMeshOrJumps(self, make_mesh):
  94. builder = MeshBuilder()
  95. for polygon in self._polygons:
  96. if make_mesh and (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
  97. continue
  98. if not make_mesh and not (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
  99. continue
  100. poly_color = polygon.getColor()
  101. points = numpy.copy(polygon.data)
  102. if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
  103. points[:,1] -= 0.01
  104. if polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
  105. points[:,1] += 0.01
  106. # Calculate normals for the entire polygon using numpy.
  107. normals = numpy.copy(points)
  108. normals[:,1] = 0.0 # We are only interested in 2D normals
  109. # Calculate the edges between points.
  110. # The call to numpy.roll shifts the entire array by one so that
  111. # we end up subtracting each next point from the current, wrapping
  112. # around. This gives us the edges from the next point to the current
  113. # point.
  114. normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0)
  115. # Calculate the length of each edge using standard Pythagoras
  116. lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2)
  117. # The normal of a 2D vector is equal to its x and y coordinates swapped
  118. # and then x inverted. This code does that.
  119. normals[:,[0, 2]] = normals[:,[2, 0]]
  120. normals[:,0] *= -1
  121. # Normalize the normals.
  122. normals[:,0] /= lengths
  123. normals[:,2] /= lengths
  124. # Scale all by the line width of the polygon so we can easily offset.
  125. normals *= (polygon.lineWidth / 2)
  126. #TODO: Use numpy magic to perform the vertex creation to speed up things.
  127. for i in range(len(points)):
  128. start = points[i - 1]
  129. end = points[i]
  130. normal = normals[i - 1]
  131. point1 = Vector(data = start - normal)
  132. point2 = Vector(data = start + normal)
  133. point3 = Vector(data = end + normal)
  134. point4 = Vector(data = end - normal)
  135. builder.addQuad(point1, point2, point3, point4, color = poly_color)
  136. return builder.getData()
  137. class Polygon():
  138. NoneType = 0
  139. Inset0Type = 1
  140. InsetXType = 2
  141. SkinType = 3
  142. SupportType = 4
  143. SkirtType = 5
  144. InfillType = 6
  145. SupportInfillType = 7
  146. MoveCombingType = 8
  147. MoveRetractionType = 9
  148. def __init__(self, mesh, type, data, line_width):
  149. super().__init__()
  150. self._mesh = mesh
  151. self._type = type
  152. self._data = data
  153. self._line_width = line_width / 1000
  154. def build(self, offset, vertices, colors, indices):
  155. self._begin = offset
  156. color = self.getColor()
  157. color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
  158. for i in range(len(self._data)):
  159. vertices[offset + i, :] = self._data[i, :]
  160. colors[offset + i, 0] = color.r
  161. colors[offset + i, 1] = color.g
  162. colors[offset + i, 2] = color.b
  163. colors[offset + i, 3] = color.a
  164. self._end = self._begin + len(self._data) - 1
  165. for i in range(self._begin, self._end):
  166. indices[i, 0] = i
  167. indices[i, 1] = i + 1
  168. indices[self._end, 0] = self._end
  169. indices[self._end, 1] = self._begin
  170. def getColor(self):
  171. if self._type == self.Inset0Type:
  172. return Color(1.0, 0.0, 0.0, 1.0)
  173. elif self._type == self.InsetXType:
  174. return Color(0.0, 1.0, 0.0, 1.0)
  175. elif self._type == self.SkinType:
  176. return Color(1.0, 1.0, 0.0, 1.0)
  177. elif self._type == self.SupportType:
  178. return Color(0.0, 1.0, 1.0, 1.0)
  179. elif self._type == self.SkirtType:
  180. return Color(0.0, 1.0, 1.0, 1.0)
  181. elif self._type == self.InfillType:
  182. return Color(1.0, 0.74, 0.0, 1.0)
  183. elif self._type == self.SupportInfillType:
  184. return Color(0.0, 1.0, 1.0, 1.0)
  185. elif self._type == self.MoveCombingType:
  186. return Color(0.0, 0.0, 1.0, 1.0)
  187. elif self._type == self.MoveRetractionType:
  188. return Color(0.0, 1.0, 1.0, 1.0)
  189. else:
  190. return Color(1.0, 1.0, 1.0, 1.0)
  191. def vertexCount(self):
  192. return len(self._data)
  193. @property
  194. def type(self):
  195. return self._type
  196. @property
  197. def data(self):
  198. return self._data
  199. @property
  200. def elementCount(self):
  201. return ((self._end - self._begin) + 1) * 2 #The range of vertices multiplied by 2 since each vertex is used twice
  202. @property
  203. def lineWidth(self):
  204. return self._line_width