Layer.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import List
  4. import numpy
  5. from UM.Mesh.MeshBuilder import MeshBuilder
  6. from UM.Mesh.MeshData import MeshData
  7. from cura.LayerPolygon import LayerPolygon
  8. class Layer:
  9. def __init__(self, layer_id: int) -> None:
  10. self._id = layer_id
  11. self._height = 0.0
  12. self._thickness = 0.0
  13. self._polygons = [] # type: List[LayerPolygon]
  14. self._element_count = 0
  15. @property
  16. def height(self):
  17. return self._height
  18. @property
  19. def thickness(self):
  20. return self._thickness
  21. @property
  22. def polygons(self) -> List[LayerPolygon]:
  23. return self._polygons
  24. @property
  25. def elementCount(self):
  26. return self._element_count
  27. def setHeight(self, height: float) -> None:
  28. self._height = height
  29. def setThickness(self, thickness: float) -> None:
  30. self._thickness = thickness
  31. def lineMeshVertexCount(self) -> int:
  32. result = 0
  33. for polygon in self._polygons:
  34. result += polygon.lineMeshVertexCount()
  35. return result
  36. def lineMeshElementCount(self) -> int:
  37. result = 0
  38. for polygon in self._polygons:
  39. result += polygon.lineMeshElementCount()
  40. return result
  41. def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices):
  42. result_vertex_offset = vertex_offset
  43. result_index_offset = index_offset
  44. self._element_count = 0
  45. for polygon in self._polygons:
  46. polygon.build(result_vertex_offset, result_index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices)
  47. result_vertex_offset += polygon.lineMeshVertexCount()
  48. result_index_offset += polygon.lineMeshElementCount()
  49. self._element_count += polygon.elementCount
  50. return result_vertex_offset, result_index_offset
  51. def createMesh(self) -> MeshData:
  52. return self.createMeshOrJumps(True)
  53. def createJumps(self) -> MeshData:
  54. return self.createMeshOrJumps(False)
  55. # Defines the two triplets of local point indices to use to draw the two faces for each line segment in createMeshOrJump
  56. __index_pattern = numpy.array([[0, 3, 2, 0, 1, 3]], dtype = numpy.int32 )
  57. def createMeshOrJumps(self, make_mesh: bool) -> MeshData:
  58. builder = MeshBuilder()
  59. line_count = 0
  60. if make_mesh:
  61. for polygon in self._polygons:
  62. line_count += polygon.meshLineCount
  63. else:
  64. for polygon in self._polygons:
  65. line_count += polygon.jumpCount
  66. # Reserve the necessary space for the data upfront
  67. builder.reserveFaceAndVertexCount(2 * line_count, 4 * line_count)
  68. for polygon in self._polygons:
  69. # Filter out the types of lines we are not interested in depending on whether we are drawing the mesh or the jumps.
  70. index_mask = numpy.logical_not(polygon.jumpMask) if make_mesh else polygon.jumpMask
  71. # Create an array with rows [p p+1] and only keep those we want to draw based on make_mesh
  72. points = numpy.concatenate((polygon.data[:-1], polygon.data[1:]), 1)[index_mask.ravel()]
  73. # Line types of the points we want to draw
  74. line_types = polygon.types[index_mask]
  75. # Shift the z-axis according to previous implementation.
  76. if make_mesh:
  77. points[polygon.isInfillOrSkinType(line_types), 1::3] -= 0.01
  78. else:
  79. points[:, 1::3] += 0.01
  80. # Create an array with normals and tile 2 copies to match size of points variable
  81. normals = numpy.tile( polygon.getNormals()[index_mask.ravel()], (1, 2))
  82. # Scale all normals by the line width of the current line so we can easily offset.
  83. normals *= (polygon.lineWidths[index_mask.ravel()] / 2)
  84. # Create 4 points to draw each line segment, points +- normals results in 2 points each.
  85. # After this we reshape to one point per line.
  86. f_points = numpy.concatenate((points-normals, points+normals), 1).reshape((-1, 3))
  87. # __index_pattern defines which points to use to draw the two faces for each lines egment, the following linesegment is offset by 4
  88. f_indices = ( self.__index_pattern + numpy.arange(0, 4 * len(normals), 4, dtype=numpy.int32).reshape((-1, 1)) ).reshape((-1, 3))
  89. f_colors = numpy.repeat(polygon.mapLineTypeToColor(line_types), 4, 0)
  90. builder.addFacesWithColor(f_points, f_indices, f_colors)
  91. return builder.build()