|
| 1 | +import bpy |
| 2 | +import math |
| 3 | +import numpy as np |
| 4 | +from .utils import draw_glyph |
| 5 | +from .utils import process_stroke_verts_linearly |
| 6 | + |
| 7 | +def ellipse(t, a, b): |
| 8 | + return [a * math.cos(t), b * math.sin(t)] |
| 9 | + |
| 10 | + |
| 11 | +def ellipse_points(origin_x, origin_y, a, b, count=100): |
| 12 | + """ |
| 13 | + Return the points that make up an ellipse with radii of a & b |
| 14 | + """ |
| 15 | + points = [] |
| 16 | + for t in np.linspace(0, 2 * math.pi, count): |
| 17 | + points.append(ellipse(t, a, b)) |
| 18 | + for point in points: |
| 19 | + point[0] += origin_x |
| 20 | + point[1] += origin_y |
| 21 | + return points |
| 22 | + |
| 23 | + |
| 24 | +def get_glyph_size(gpencil): |
| 25 | + """ |
| 26 | + Get the size of a grease_pencil object |
| 27 | + """ |
| 28 | + layer = gpencil.layers[0] |
| 29 | + frame = layer.frames[-1] |
| 30 | + |
| 31 | + x_points = [] |
| 32 | + y_points = [] |
| 33 | + for stroke in frame.strokes: |
| 34 | + for point in stroke.points: |
| 35 | + x_points.append(point.co.x) |
| 36 | + y_points.append(point.co.y) |
| 37 | + |
| 38 | + min_x = min(x_points) |
| 39 | + max_x = max(x_points) |
| 40 | + |
| 41 | + min_y = min(y_points) |
| 42 | + max_y = max(y_points) |
| 43 | + |
| 44 | + return min_x, max_x, min_y, max_y |
| 45 | + |
| 46 | + |
| 47 | +class GREASEPENCIL_OT_decorate(bpy.types.Operator): |
| 48 | + bl_label = "Decorate" |
| 49 | + bl_idname = "grease_writer.decorate" |
| 50 | + bl_description = "Decorates the selected grease pencil layer" |
| 51 | + bl_options = {"REGISTER", "UNDO"} |
| 52 | + |
| 53 | + @classmethod |
| 54 | + def poll(self, context): |
| 55 | + obj = bpy.context.view_layer.objects.active |
| 56 | + gpencil = obj.data |
| 57 | + if (len(gpencil.layers) > 0 and |
| 58 | + len(gpencil.layers[0].frames) > 0): |
| 59 | + return True |
| 60 | + else: |
| 61 | + return False |
| 62 | + |
| 63 | + def execute(self, context): |
| 64 | + obj = bpy.context.view_layer.objects.active |
| 65 | + gpencil = obj.data |
| 66 | + |
| 67 | + obj_name = obj.name |
| 68 | + speed = gpencil.draw_speed |
| 69 | + thickness = gpencil.write_thickness |
| 70 | + line_height = gpencil.line_height |
| 71 | + |
| 72 | + color = gpencil.write_color |
| 73 | + |
| 74 | + left, right, bottom, top = get_glyph_size(gpencil) |
| 75 | + width = right - left |
| 76 | + height = top - bottom |
| 77 | + |
| 78 | + style = gpencil.decorator_style |
| 79 | + thickness = gpencil.write_thickness |
| 80 | + |
| 81 | + glyph_strokes = [] |
| 82 | + |
| 83 | + padding_fac = 0.125 |
| 84 | + |
| 85 | + origin_x = (width / 2) + left |
| 86 | + origin_y = (height / 2) + bottom |
| 87 | + |
| 88 | + if style == "underline": |
| 89 | + v1 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 90 | + v2 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 91 | + glyph_strokes.append([v1, v2]) |
| 92 | + |
| 93 | + elif style == "over-underline": |
| 94 | + v1 = [left - (width * padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y] |
| 95 | + v2 = [right * (1 + padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y] |
| 96 | + glyph_strokes.append([v1, v2]) |
| 97 | + |
| 98 | + v1 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 99 | + v2 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 100 | + glyph_strokes.append([v1, v2]) |
| 101 | + |
| 102 | + elif style == "x-out": |
| 103 | + v1 = [left - (width * padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y] |
| 104 | + v2 = [right * (1 + padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y] |
| 105 | + v3 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 106 | + v4 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 107 | + glyph_strokes.append([v1, v3]) |
| 108 | + glyph_strokes.append([v2, v4]) |
| 109 | + |
| 110 | + elif style == "strike-through": |
| 111 | + v1 = [left - (width * padding_fac) - origin_x, bottom + (height / 2) - origin_y] |
| 112 | + v2 = [right * (1 + padding_fac) - origin_x, bottom + (height / 2) - origin_y] |
| 113 | + glyph_strokes.append([v1, v2]) |
| 114 | + |
| 115 | + elif style == "box": |
| 116 | + v1 = [left - (width * padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y] |
| 117 | + v2 = [right * (1 + padding_fac) - origin_x, top + (line_height * padding_fac) - origin_y] |
| 118 | + v3 = [right * (1 + padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 119 | + v4 = [left - (width * padding_fac) - origin_x, bottom - (line_height * padding_fac) - origin_y] |
| 120 | + glyph_strokes.append([v1, v2, v3, v4, v1]) |
| 121 | + |
| 122 | + elif style == "ellipse": |
| 123 | + w_fac = height / width |
| 124 | + h_fac = width / height |
| 125 | + |
| 126 | + a = (width / 2) + (width * (padding_fac * 3) * w_fac) |
| 127 | + b = (height / 2) + (height * (padding_fac * 3) * h_fac) |
| 128 | + glyph_strokes.append(ellipse_points(0, 0, a, b)) |
| 129 | + |
| 130 | + elif style == "circle": |
| 131 | + if width > height: |
| 132 | + longer = width |
| 133 | + elif height > width: |
| 134 | + longer = height |
| 135 | + a = (longer / 2) + (longer * padding_fac) |
| 136 | + b = (longer / 2) + (longer * padding_fac) |
| 137 | + glyph_strokes.append(ellipse_points(0, 0, a, b)) |
| 138 | + |
| 139 | + elif style == "helioid": |
| 140 | + if width > height: |
| 141 | + w_fac = height / width |
| 142 | + h_fac = width / height |
| 143 | + a = (width / 2) + (width * (padding_fac * 3) * w_fac) |
| 144 | + b = (height / 2) + (height * (padding_fac * 3) * h_fac) |
| 145 | + glyph_strokes.append(ellipse_points(0, 0, a, b)) |
| 146 | + |
| 147 | + longer = max([a, b]) |
| 148 | + |
| 149 | + starts = ellipse_points(0, 0, a * (1 + padding_fac * 2), b * (1 + padding_fac * 2), count=12) |
| 150 | + ends = ellipse_points(0, 0, a * (1 + padding_fac * 2) + (longer / 3), b * (1 + padding_fac * 2) + (longer / 3), count=12) |
| 151 | + |
| 152 | + for i in range(len(starts)): |
| 153 | + glyph_strokes.append([starts[i], ends[i]]) |
| 154 | + |
| 155 | + |
| 156 | + last_point = gpencil.layers[0].frames[-1].strokes[-1].points[-1] |
| 157 | + last_vert = [last_point.co.x, last_point.co.y] |
| 158 | + new_vert = glyph_strokes[0][0] |
| 159 | + count = len(process_stroke_verts_linearly([last_vert, new_vert], speed)) - 1 |
| 160 | + |
| 161 | + bpy.context.scene.frame_current = gpencil.layers[0].frames[-1].frame_number + count |
| 162 | + |
| 163 | + new_gpencil = bpy.data.grease_pencil.new('gpencil') |
| 164 | + new_gpencil.draw_speed = speed |
| 165 | + new_gpencil.write_thickness = thickness |
| 166 | + new_gpencil.write_color = gpencil.write_color |
| 167 | + |
| 168 | + new_obj = bpy.data.objects.new(obj_name + '_' + style, new_gpencil) |
| 169 | + bpy.context.scene.collection.objects.link(new_obj) |
| 170 | + new_obj.location[0] = origin_x |
| 171 | + new_obj.location[1] = origin_y |
| 172 | + |
| 173 | + new_obj.empty_display_size = 0.2 |
| 174 | + new_obj.parent = obj |
| 175 | + |
| 176 | + bpy.context.view_layer.objects.active = new_obj |
| 177 | + |
| 178 | + draw_glyph(glyph_strokes) |
| 179 | + |
| 180 | + return {"FINISHED"} |
0 commit comments