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 = BoundingBox.from_sequence(svert.point for svert in stroke).corners 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 # dependent 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): # 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()