LayerData.py 7.3 KB

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