GP: Draw Mode: Add Arc Primitive
authorCharlie Jolly <mistajolly@gmail.com>
Mon, 3 Dec 2018 14:55:57 +0000 (14:55 +0000)
committerCharlie Jolly <mistajolly@gmail.com>
Mon, 3 Dec 2018 22:11:38 +0000 (22:11 +0000)
This adds an elliptical arc primitive.
Press CKEY for toggling closed/open arc.
Press FKEY key for flipping arc.

Additional changes to gpencil primitives.
Increases default edges of circle to 64.
Keymap changes to allow primitives to be drawn with Shift or Alt key.
Allow Plus/Minus key to adjust number of edges.

Missing: Toolbar icon

Differential Revision: https://developer.blender.org/D4024

release/scripts/presets/keyconfig/keymap_data/blender_default.py
release/scripts/startup/bl_ui/properties_grease_pencil_common.py
release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
release/scripts/startup/bl_ui/space_topbar.py
source/blender/editors/gpencil/gpencil_intern.h
source/blender/editors/gpencil/gpencil_primitive.c

index ddcd4242c4a6446fb9635f9ddd2bb226619786b8..09fdd2029326d6e26516fe79f1380b46a9da4da8 100644 (file)
@@ -5646,6 +5646,10 @@ def km_3d_view_tool_gpencil_paint_line(params):
         {"items": [
             ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'},
              {"properties": [("type", 'LINE'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+             {"properties": [("type", 'LINE'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
+             {"properties": [("type", 'LINE'), ("wait_for_input", False)]}),
         ]},
     )
 
@@ -5657,6 +5661,10 @@ def km_3d_view_tool_gpencil_paint_box(params):
         {"items": [
             ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'},
              {"properties": [("type", 'BOX'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+             {"properties": [("type", 'BOX'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
+             {"properties": [("type", 'BOX'), ("wait_for_input", False)]}),
         ]},
     )
 
@@ -5668,6 +5676,25 @@ def km_3d_view_tool_gpencil_paint_circle(params):
         {"items": [
             ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'},
              {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+             {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
+             {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}),
+        ]},
+    )
+
+
+def km_3d_view_tool_gpencil_paint_arc(params):
+    return (
+        "3D View Tool: Gpencil Paint, Arc",
+        {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+        {"items": [
+            ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'},
+             {"properties": [("type", 'ARC'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+             {"properties": [("type", 'ARC'), ("wait_for_input", False)]}),
+            ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
+             {"properties": [("type", 'ARC'), ("wait_for_input", False)]}),
         ]},
     )
 
@@ -5944,6 +5971,7 @@ def generate_keymaps(params=None):
         km_3d_view_tool_gpencil_paint_line(params),
         km_3d_view_tool_gpencil_paint_box(params),
         km_3d_view_tool_gpencil_paint_circle(params),
+        km_3d_view_tool_gpencil_paint_arc(params),
         km_3d_view_tool_gpencil_edit_select(params),
         km_3d_view_tool_gpencil_edit_select_box(params),
         km_3d_view_tool_gpencil_edit_select_circle(params),
index eed78ff26ad17feb4590e147f49bea2c9d494d22..5a0c2bd1e433ac54478c9bc77bbfc7ff54abd1c9 100644 (file)
@@ -644,6 +644,7 @@ class GPENCIL_MT_gpencil_draw_specials(Menu):
         layout.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE'
         layout.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX'
         layout.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE'
+        layout.operator("gpencil.primitive", text="Arc", icon='SPHERECURVE').type = 'ARC'
 
 
 class GPENCIL_MT_gpencil_draw_delete(Menu):
index 591a17db4a53a25143a53c050b99c6dc8bc1247e..5c930b68dd9a88e9a2d73720066fc9516788e41d 100644 (file)
@@ -1067,6 +1067,15 @@ class _defs_gpencil_paint:
             keymap=(),
         )
 
+    @ToolDef.from_fn
+    def arc():
+        return dict(
+            text="Arc",
+            icon="ops.gpencil.primitive_arc",
+            cursor='CROSSHAIR',
+            widget=None,
+            keymap=(),
+        )
 
 class _defs_gpencil_edit:
     @ToolDef.from_fn
@@ -1573,6 +1582,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
             _defs_gpencil_paint.line,
             _defs_gpencil_paint.box,
             _defs_gpencil_paint.circle,
+            _defs_gpencil_paint.arc,
         ],
         'GPENCIL_EDIT': [
             *_tools_gpencil_select,
index f1a91d0804084e55822bf8669fc64ed2822a30d1..af1f72fa72c1dc8947495ad6850d0ff4ce19eab0 100644 (file)
@@ -301,7 +301,7 @@ class _draw_left_context_mode:
                 return
 
             is_paint = True
-            if (tool.name in {"Line", "Box", "Circle"}):
+            if (tool.name in {"Line", "Box", "Circle", "Arc"}):
                 is_paint = False
             elif (not tool.has_datablock):
                 return
index 93d75063bff1bfec063e11198c1daed712010e10..5db5c0f25716a98c06ba52ba715f5c1659aa649e 100644 (file)
@@ -154,6 +154,8 @@ typedef struct tGPDprimitive {
        struct bGPDlayer *gpl;            /* layer */
        struct bGPDframe *gpf;            /* frame */
        int type;                         /* type of primitive */
+       short cyclic;                       /* cyclic option */
+       short flip;                         /* flip option */
        int tot_edges;                    /* number of polygon edges */
        int top[2];                       /* first box corner */
        int bottom[2];                    /* last box corner */
@@ -369,7 +371,8 @@ enum {
 enum {
        GP_STROKE_BOX = -1,
        GP_STROKE_LINE = 1,
-       GP_STROKE_CIRCLE = 2
+       GP_STROKE_CIRCLE = 2,
+       GP_STROKE_ARC = 3
 };
 
 
index 336ed305a93398168a8942642fa95ec97387c1cd..140a7527dc983ead0fc6320f8fac5767a1ae7053 100644 (file)
@@ -84,7 +84,7 @@
 #include "gpencil_intern.h"
 
 #define MIN_EDGES 2
-#define MAX_EDGES 100
+#define MAX_EDGES 128
 
 #define IDLE 0
 #define IN_PROGRESS 1
@@ -168,7 +168,7 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
        /* enable recalculation flag by default */
        gps->flag |= GP_STROKE_RECALC_CACHES;
        /* the polygon must be closed, so enabled cyclic */
-       if (tgpi->type != GP_STROKE_LINE) {
+       if (tgpi->type != GP_STROKE_LINE && tgpi->type != GP_STROKE_ARC) {
                gps->flag |= GP_STROKE_CYCLIC;
        }
        else {
@@ -215,11 +215,14 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
        else if (tgpi->type == GP_STROKE_LINE) {
                BLI_strncpy(msg_str, IFACE_("Line: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Alt to center"), UI_MAX_DRAW_STR);
        }
+       else if (tgpi->type == GP_STROKE_ARC) {
+               BLI_strncpy(msg_str, IFACE_("Arc: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center, F to flip, C to Close"), UI_MAX_DRAW_STR);
+       }
        else {
-               BLI_strncpy(msg_str, IFACE_("Circle: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL to adjust edge number, Shift to square, Alt to center"), UI_MAX_DRAW_STR);
+               BLI_strncpy(msg_str, IFACE_("Circle: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/+- to adjust edge number, Shift to square, Alt to center"), UI_MAX_DRAW_STR);
        }
 
-       if (tgpi->type == GP_STROKE_CIRCLE) {
+       if (tgpi->type == GP_STROKE_CIRCLE || tgpi->type == GP_STROKE_ARC) {
                if (hasNumInput(&tgpi->num)) {
                        char str_offs[NUM_STR_REP_LEN];
 
@@ -286,6 +289,37 @@ static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
        points2D[1].y = tgpi->bottom[1];
 }
 
+/* create an arc */
+static void gp_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+       const int totpoints = tgpi->tot_edges;
+       const float step = M_PI_2 / (float)(totpoints - 1);
+       float length[2];
+       int start[2];
+       int end[2];
+       float a = 0.0f;
+
+       start[0] = tgpi->top[0];
+       start[1] = tgpi->top[1];
+       end[0] = tgpi->bottom[0];
+       end[1] = tgpi->bottom[1];
+
+       if (tgpi->flip) {
+               SWAP(int, end[0], start[0]);
+               SWAP(int, end[1], start[1]);
+       }
+       
+       length[0] = end[0] - start[0];
+       length[1] = end[1] - start[1];
+
+       for (int i = 0; i < totpoints; i++) {
+               tGPspoint *p2d = &points2D[i];
+               p2d->x = (int)(start[0] + sinf(a) * length[0]);
+               p2d->y = (int)(end[1] - cosf(a) * length[1]);
+               a += step;
+       }
+}
+
 /* create a circle */
 static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
 {
@@ -337,6 +371,13 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
                case GP_STROKE_CIRCLE:
                        gp_primitive_circle(tgpi, points2D);
                        break;
+               case GP_STROKE_ARC:
+                       gp_primitive_arc(tgpi, points2D);
+                       if (tgpi->cyclic)
+                               gps->flag |= GP_STROKE_CYCLIC;
+                       else
+                               gps->flag &= ~GP_STROKE_CYCLIC;
+                       break;
                default:
                        break;
        }
@@ -346,7 +387,6 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
                bGPDspoint *pt = &gps->points[i];
                tGPspoint *p2d = &points2D[i];
 
-
                /* convert screen-coordinates to 3D coordinates */
                gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, p2d, NULL, &pt->x);
 
@@ -447,7 +487,7 @@ static void gpencil_primitive_exit(bContext *C, wmOperator *op)
 }
 
 /* Init new temporary primitive data */
-static void gpencil_primitive_init(bContext *C, wmOperator *op)
+static void gpencil_primitive_init(bContext *C, wmOperator *op, const wmEvent *event)
 {
        ToolSettings *ts = CTX_data_tool_settings(C);
        bGPdata *gpd = CTX_data_gpencil_data(C);
@@ -482,8 +522,11 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
        /* set parameters */
        tgpi->type = RNA_enum_get(op->ptr, "type");
 
-       /* if circle set default to 32 */
+       /* set default edge count */
        if (tgpi->type == GP_STROKE_CIRCLE) {
+               RNA_int_set(op->ptr, "edges", 64);
+       }
+       else if (tgpi->type == GP_STROKE_ARC) {
                RNA_int_set(op->ptr, "edges", 32);
        }
        else if (tgpi->type == GP_STROKE_BOX) {
@@ -512,7 +555,7 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
        tGPDprimitive *tgpi = NULL;
 
        /* initialize operator runtime data */
-       gpencil_primitive_init(C, op);
+       gpencil_primitive_init(C, op, event);
        tgpi = op->customdata;
 
        const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
@@ -647,7 +690,6 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
                        /* done! */
                        return OPERATOR_FINISHED;
                }
-
                case ESCKEY:    /* cancel */
                case RIGHTMOUSE:
                {
@@ -661,10 +703,30 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
                        /* canceled! */
                        return OPERATOR_CANCELLED;
                }
+               case CKEY:
+               {
+                       if ((event->val == KM_RELEASE) && tgpi->type == GP_STROKE_ARC) {
+                               tgpi->cyclic ^= 1;
+
+                               /* update screen */
+                               gpencil_primitive_update(C, op, tgpi);
+                       }
+                       break;
+               }
+               case FKEY:
+               {
+                       if ((event->val == KM_RELEASE) && tgpi->type == GP_STROKE_ARC) {
+                               tgpi->flip ^= 1;
 
+                               /* update screen */
+                               gpencil_primitive_update(C, op, tgpi);
+                       }
+                       break;
+               }
+               case PADPLUSKEY:
                case WHEELUPMOUSE:
                {
-                       if (tgpi->type == GP_STROKE_CIRCLE) {
+                       if ((event->val != KM_RELEASE) && (tgpi->type == GP_STROKE_CIRCLE || tgpi->type == GP_STROKE_ARC)) {
                                tgpi->tot_edges = tgpi->tot_edges + 1;
                                CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
                                RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
@@ -674,9 +736,10 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
                        }
                        break;
                }
+               case PADMINUS:
                case WHEELDOWNMOUSE:
                {
-                       if (tgpi->type == GP_STROKE_CIRCLE) {
+                       if ((event->val != KM_RELEASE) && (tgpi->type == GP_STROKE_CIRCLE || tgpi->type == GP_STROKE_ARC)) {
                                tgpi->tot_edges = tgpi->tot_edges - 1;
                                CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
                                RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
@@ -771,6 +834,7 @@ void GPENCIL_OT_primitive(wmOperatorType *ot)
                {GP_STROKE_BOX, "BOX", 0, "Box", ""},
                {GP_STROKE_LINE, "LINE", 0, "Line", ""},
                {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
+               {GP_STROKE_ARC, "ARC", 0, "Arc", ""},
                {0, NULL, 0, NULL, NULL}
        };