def shade(self, stroke): p_min, p_max = bounding_box(stroke) stroke.resample(32 * self.__turns) sv_nb = len(stroke) // self.__turns center = (p_min + p_max) / 2 radius = center - p_min R = self.__random_radius C = self.__random_center # for description of the line below, see pyBluePrintCirclesShader directions = phase_to_direction(sv_nb) it = iter(stroke) for j in range(self.__turns): prev_radius = radius prev_center = center radius = radius + Vector((randint(-R, R), randint(-R, R))) center = center + Vector((randint(-C, C), randint(-C, C))) for (phase, direction), svert in zip(directions, it): r = prev_radius + (radius - prev_radius) * phase c = prev_center + (center - prev_center) * phase svert.point = (c.x + r.x * direction.x, c.y + r.y * direction.y) # remove excess vertices if not it.is_end: it.increment() for sv in tuple(it): stroke.remove_vertex(sv) stroke.update_length()
def shade(self, stroke): # get minimum and maximum coordinates p_min, p_max = bounding_box(stroke) stroke.resample(32 * self.__turns) sv_nb = len(stroke) // self.__turns center = (p_min + p_max) / 2 radius = (center.x - p_min.x + center.y - p_min.y) / 2 R = self.__random_radius C = self.__random_center # The directions (and phases) are calculated using a separate # function decorated with an lru-cache. This guarantees that # the directions (involving sin and cos) are calculated as few # times as possible. # # This works because the phases and directions are only # dependant on the stroke length, and the chance that # stroke.resample() above produces strokes of the same length # is quite high. # # In tests, the amount of calls to sin() and cos() went from # over 21000 to just 32 times, yielding a speedup of over 100% directions = phase_to_direction(sv_nb) it = iter(stroke) for j in range(self.__turns): prev_radius = radius prev_center = center radius += randint(-R, R) center += Vector((randint(-C, C), randint(-C, C))) for (phase, direction), svert in zip(directions, it): r = prev_radius + (radius - prev_radius) * phase c = prev_center + (center - prev_center) * phase svert.point = c + r * direction if not it.is_end: it.increment() for sv in tuple(it): stroke.remove_vertex(sv) stroke.update_length()
def shade(self, stroke): # this condition will lead to errors later, end now if len(stroke) < 1: return # get minimum and maximum coordinates p_min, p_max = bounding_box(stroke) stroke.resample(32 * self.__turns) num_segments = len(stroke) // self.__turns f = num_segments // 4 # indices of the vertices that will form corners first, second, third, fourth = (f, f * 2, f * 3, num_segments) # construct points of the backbone bb_len = self.__bb_len points = ( Vector((p_min.x - bb_len, p_min.y)), Vector((p_max.x + bb_len, p_min.y)), Vector((p_max.x, p_min.y - bb_len)), Vector((p_max.x, p_max.y + bb_len)), Vector((p_max.x + bb_len, p_max.y)), Vector((p_min.x - bb_len, p_max.y)), Vector((p_min.x, p_max.y + bb_len)), Vector((p_min.x, p_min.y - bb_len)), ) # add randomization to the points (if needed) if self.__bb_rand: R, r = self.__bb_rand, self.__bb_rand // 2 randomization_mat = ( Vector((randint(-R, R), randint(-r, r))), Vector((randint(-R, R), randint(-r, r))), Vector((randint(-r, r), randint(-R, R))), Vector((randint(-r, r), randint(-R, R))), Vector((randint(-R, R), randint(-r, r))), Vector((randint(-R, R), randint(-r, r))), Vector((randint(-r, r), randint(-R, R))), Vector((randint(-r, r), randint(-R, R))), ) # combine both tuples points = tuple(p + rand for (p, rand) in zip(points, randomization_mat)) # subtract even from uneven; result is length four tuple of vectors it = iter(points) old_vecs = tuple(next(it) - current for current in it) it = iter(stroke) verticesToRemove = list() for j in range(self.__turns): for i, svert in zip(range(num_segments), it): if i < first: svert.point = points[0] + old_vecs[0] * i / (first - 1) svert.attribute.visible = (i != first - 1) elif i < second: svert.point = points[2] + old_vecs[1] * (i - first) / ( second - first - 1) svert.attribute.visible = (i != second - 1) elif i < third: svert.point = points[4] + old_vecs[2] * (i - second) / ( third - second - 1) svert.attribute.visible = (i != third - 1) elif i < fourth: svert.point = points[6] + old_vecs[3] * (i - third) / ( fourth - third - 1) svert.attribute.visible = (i != fourth - 1) else: # special case; remove these vertices verticesToRemove.append(svert) # remove excess vertices (if any) if not it.is_end: it.increment() verticesToRemove += [svert for svert in it] for sv in verticesToRemove: stroke.remove_vertex(sv) stroke.update_length()
def shade(self, stroke): # this condition will lead to errors later, end now if len(stroke) < 1: return # get minimum and maximum coordinates p_min, p_max = bounding_box(stroke) stroke.resample(32 * self.__turns) num_segments = len(stroke) // self.__turns f = num_segments // 4 # indices of the vertices that will form corners first, second, third, fourth = (f, f * 2, f * 3, num_segments) # construct points of the backbone bb_len = self.__bb_len points = ( Vector((p_min.x - bb_len, p_min.y)), Vector((p_max.x + bb_len, p_min.y)), Vector((p_max.x, p_min.y - bb_len)), Vector((p_max.x, p_max.y + bb_len)), Vector((p_max.x + bb_len, p_max.y)), Vector((p_min.x - bb_len, p_max.y)), Vector((p_min.x, p_max.y + bb_len)), Vector((p_min.x, p_min.y - bb_len)), ) # add randomization to the points (if needed) if self.__bb_rand: R, r = self.__bb_rand, self.__bb_rand // 2 randomization_mat = ( Vector((randint(-R, R), randint(-r, r))), Vector((randint(-R, R), randint(-r, r))), Vector((randint(-r, r), randint(-R, R))), Vector((randint(-r, r), randint(-R, R))), Vector((randint(-R, R), randint(-r, r))), Vector((randint(-R, R), randint(-r, r))), Vector((randint(-r, r), randint(-R, R))), Vector((randint(-r, r), randint(-R, R))), ) # combine both tuples points = tuple(p + rand for (p, rand) in zip(points, randomization_mat)) # subtract even from uneven; result is length four tuple of vectors it = iter(points) old_vecs = tuple(next(it) - current for current in it) it = iter(stroke) verticesToRemove = list() for j in range(self.__turns): for i, svert in zip(range(num_segments), it): if i < first: svert.point = points[0] + old_vecs[0] * i / (first - 1) svert.attribute.visible = (i != first - 1) elif i < second: svert.point = points[2] + old_vecs[1] * (i - first) / (second - first - 1) svert.attribute.visible = (i != second - 1) elif i < third: svert.point = points[4] + old_vecs[2] * (i - second) / (third - second - 1) svert.attribute.visible = (i != third - 1) elif i < fourth: svert.point = points[6] + old_vecs[3] * (i - third) / (fourth - third - 1) svert.attribute.visible = (i != fourth - 1) else: # special case; remove these vertices verticesToRemove.append(svert) # remove excess vertices (if any) if not it.is_end: it.increment() verticesToRemove += [svert for svert in it] for sv in verticesToRemove: stroke.remove_vertex(sv) stroke.update_length()