Welcome to mirror list, hosted at ThFree Co, Russian Federation.

LayerPolygon.py « cura - github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: cb00bd0c609d08c4ec425f08d55828a285f9deb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
from UM.Math.Color import Color

import numpy


class LayerPolygon:
    NoneType = 0
    Inset0Type = 1
    InsetXType = 2
    SkinType = 3
    SupportType = 4
    SkirtType = 5
    InfillType = 6
    SupportInfillType = 7
    MoveCombingType = 8
    MoveRetractionType = 9
    SupportInterfaceType = 10
    
    __jump_map = numpy.logical_or(numpy.logical_or(numpy.arange(11) == NoneType, numpy.arange(11) == MoveCombingType), numpy.arange(11) == MoveRetractionType)
    
    def __init__(self, mesh, extruder, line_types, data, line_widths):
        self._mesh = mesh
        self._extruder = extruder
        self._types = line_types
        self._data = data
        self._line_widths = line_widths
        
        self._vertex_begin = 0
        self._vertex_end = 0
        self._index_begin = 0
        self._index_end = 0
        
        self._jump_mask = self.__jump_map[self._types]
        self._jump_count = numpy.sum(self._jump_mask)
        self._mesh_line_count = len(self._types)-self._jump_count
        self._vertex_count = self._mesh_line_count + numpy.sum( self._types[1:] == self._types[:-1])

        # Buffering the colors shouldn't be necessary as it is not 
        # re-used and can save alot of memory usage.
        self._color_map = self.__color_map * [1, 1, 1, self._extruder] # The alpha component is used to store the extruder nr
        self._colors = self._color_map[self._types]
        
        # When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
        # Should be generated in better way, not hardcoded.
        self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1], dtype=numpy.bool)
        
        self._build_cache_line_mesh_mask = None
        self._build_cache_needed_points = None
        
    def buildCache(self):
        # For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out.
        self._build_cache_line_mesh_mask = numpy.logical_not(numpy.logical_or(self._jump_mask, self._types == LayerPolygon.InfillType ))
        mesh_line_count = numpy.sum(self._build_cache_line_mesh_mask)
        self._index_begin = 0
        self._index_end = mesh_line_count
        
        self._build_cache_needed_points = numpy.ones((len(self._types), 2), dtype=numpy.bool)
        # Only if the type of line segment changes do we need to add an extra vertex to change colors
        self._build_cache_needed_points[1:, 0][:, numpy.newaxis] = self._types[1:] != self._types[:-1]
        # Mark points as unneeded if they are of types we don't want in the line mesh according to the calculated mask
        numpy.logical_and(self._build_cache_needed_points, self._build_cache_line_mesh_mask, self._build_cache_needed_points )
        
        self._vertex_begin = 0
        self._vertex_end = numpy.sum( self._build_cache_needed_points )
        

    def build(self, vertex_offset, index_offset, vertices, colors, indices):
        if (self._build_cache_line_mesh_mask is None) or (self._build_cache_needed_points is None ):
            self.buildCache()
            
        line_mesh_mask = self._build_cache_line_mesh_mask
        needed_points_list = self._build_cache_needed_points
        
        # Index to the points we need to represent the line mesh. This is constructed by generating simple
        # start and end points for each line. For line segment n these are points n and n+1. Row n reads [n n+1] 
        # Then then the indices for the points we don't need are thrown away based on the pre-calculated list. 
        index_list = ( numpy.arange(len(self._types)).reshape((-1, 1)) + numpy.array([[0, 1]]) ).reshape((-1, 1))[needed_points_list.reshape((-1, 1))]
        
        # The relative values of begin and end indices have already been set in buildCache, so we only need to offset them to the parents offset.
        self._vertex_begin += vertex_offset
        self._vertex_end += vertex_offset
        
        # Points are picked based on the index list to get the vertices needed. 
        vertices[self._vertex_begin:self._vertex_end, :] = self._data[index_list, :]
        # Create an array with colors for each vertex and remove the color data for the points that has been thrown away. 
        colors[self._vertex_begin:self._vertex_end, :] = numpy.tile(self._colors, (1, 2)).reshape((-1, 4))[needed_points_list.ravel()] 
        colors[self._vertex_begin:self._vertex_end, :] *= numpy.array([[0.5, 0.5, 0.5, 1.0]], numpy.float32)

        # The relative values of begin and end indices have already been set in buildCache, so we only need to offset them to the parents offset.
        self._index_begin += index_offset
        self._index_end += index_offset
        
        indices[self._index_begin:self._index_end, :] = numpy.arange(self._index_end-self._index_begin, dtype=numpy.int32).reshape((-1, 1))
        # When the line type changes the index needs to be increased by 2.
        indices[self._index_begin:self._index_end, :] += numpy.cumsum(needed_points_list[line_mesh_mask.ravel(), 0], dtype=numpy.int32).reshape((-1, 1))
        # Each line segment goes from it's starting point p to p+1, offset by the vertex index. 
        # The -1 is to compensate for the neccecarily True value of needed_points_list[0,0] which causes an unwanted +1 in cumsum above.
        indices[self._index_begin:self._index_end, :] += numpy.array([self._vertex_begin - 1, self._vertex_begin])
        
        self._build_cache_line_mesh_mask = None
        self._build_cache_needed_points = None

    def getColors(self):
        return self._colors

    def mapLineTypeToColor(self, line_types):
        return self._color_map[line_types]

    def isInfillOrSkinType(self, line_types):
        return self._isInfillOrSkinTypeMap[line_types]

    def lineMeshVertexCount(self):
        return (self._vertex_end - self._vertex_begin)

    def lineMeshElementCount(self):
        return (self._index_end - self._index_begin)

    @property
    def extruder(self):
        return self._extruder

    @property
    def types(self):
        return self._types

    @property
    def data(self):
        return self._data

    @property
    def elementCount(self):
        return (self._index_end - self._index_begin) * 2  # The range of vertices multiplied by 2 since each vertex is used twice

    @property
    def lineWidths(self):
        return self._line_widths
    
    @property
    def jumpMask(self):
        return self._jump_mask

    @property
    def meshLineCount(self):
        return self._mesh_line_count

    @property
    def jumpCount(self):
        return self._jump_count

    # Calculate normals for the entire polygon using numpy.
    def getNormals(self):
        normals = numpy.copy(self._data)
        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 = numpy.diff(normals, 1, 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

        return normals

    # Should be generated in better way, not hardcoded.
    __color_map = numpy.array([
        [1.0,  1.0,  1.0, 1.0], # NoneType
        [1.0,  0.0,  0.0, 1.0], # Inset0Type
        [0.0,  1.0,  0.0, 1.0], # InsetXType
        [1.0,  1.0,  0.0, 1.0], # SkinType
        [0.0,  1.0,  1.0, 1.0], # SupportType
        [0.0,  1.0,  1.0, 1.0], # SkirtType
        [1.0,  0.75, 0.0, 1.0], # InfillType
        [0.0,  1.0,  1.0, 1.0], # SupportInfillType
        [0.0,  0.0,  1.0, 1.0], # MoveCombingType
        [0.5,  0.5,  1.0, 1.0], # MoveRetractionType
        [0.25, 0.75, 1.0, 1.0]  # SupportInterfaceType
    ])