Skip to content

PLUGIN: Multiple - Wall of code for OP8 and OP12 #24

Description

@Danweel

Very difficult to observe (it's 50 lines I think?) though it walks through the logic steps, consider:

def op8(context: bpy.types.Context) -> None:
    """Apply random noise to strokes to simulate hand-drawn jitter."""
    
    # 1. Prepare the canvas
    bpy.ops.object.mode_set(mode='EDIT_GPENCIL')
    
    # 2. Apply the "Jitter" effect (The core logic)
    _apply_jitter_pattern(context, iterations=2)
    
    # 3. Apply thickness variation
    _apply_thickness_variation(context)
    
    # 4. Cleanup
    bpy.ops.gpencil.select_all(action='DESELECT')
    bpy.ops.object.mode_set(mode='PAINT_GPENCIL')
    bpy.ops.ed.undo_push(message="Randomize Line Art")

this is what this is trying to do:

def op8(context):
    _do_jitter_step_1(context)
    _do_jitter_step_2(context)
    _do_thickness(context)

def _do_jitter_step_1(context):
    # ... logic for step 1 ...

def _do_jitter_step_2(context):
    # ... logic for step 2 ...

Which makes it easier for maintainers and forkers to work with.

  • If the "Thickness" part is broken, you can look at _apply_thickness_variation in isolation. You don't have to scroll through 100 lines of selection logic to find the bug.
  • If you ever want to test just the thickness logic, you can call that helper function directly.
  • If you want to change the "Jitter" to only happen 3 times instead of 4, you just change the loop inside the helper function, rather than hunting through the main function

That's the idea anyway.

?? needs testing:

# --- CONSTANTS ---
MYBRUSHSIZE: int = 13

# --- HELPER FUNCTIONS (The "Ingredients") ---
# These are private helpers, not meant to be called by users directly.
# They are prefixed with _ to indicate they are internal.

def _toggle_select_mode(context: bpy.types.Context, mode: int) -> None:
    """Helper to toggle selection mode safely."""
    bpy.ops.gpencil.selectmode_toggle(mode=mode)

def _apply_noise_step(context: bpy.types.Context, x: float, y: float, size: float) -> None:
    """Applies one direction of noise to the selection."""
    bpy.ops.gpencil.select_all(action='SELECT')
    bpy.ops.gpencil.selectmode_toggle(mode=0)
    bpy.ops.gpencil.select_random(ratio=0.995, seed=random.randint(0, 255), action='DESELECT', unselect_ends=False)
    bpy.ops.transform.translate(
        value=(x, y, 0), 
        orient_type='VIEW', 
        use_proportional_edit=True, 
        proportional_edit_falloff='SMOOTH', 
        proportional_size=size, 
        gpencil_strokes=True
    )

def _apply_thickness_variation(context: bpy.types.Context, factor: float) -> None:
    """Applies thickness variation to the selection."""
    bpy.ops.transform.transform(
        mode='GPENCIL_SHRINKFATTEN', 
        value=(factor, 1, 1, 1), 
        use_proportional_edit=True, 
        proportional_edit_falloff='SMOOTH', 
        proportional_size=10, 
        use_proportional_connected=True, 
        gpencil_strokes=True
    )

# --- OPERATORS ---

class SimpleOperatorOP8(bpy.types.Operator):
    bl_idname = "fred.op8"
    bl_label = "Randomize Line Art"

    def execute(self, context: bpy.types.Context) -> {'FINISHED'}:
        # The operator becomes a clear list of steps
        bpy.ops.object.mode_set(mode='EDIT_GPENCIL')
        
        # Run the noise pattern 4 times with different directions
        _apply_noise_step(context, 0.0005, 0.0005, 0.01)
        _apply_noise_step(context, -0.0005, -0.0005, 0.01)
        _apply_noise_step(context, -0.0005, 0.0005, 0.01)
        _apply_noise_step(context, 0.0005, -0.0005, 0.01)
        
        # Apply thickness
        _apply_thickness_variation(context, 1.0)
        
        # Cleanup
        bpy.ops.gpencil.select_all(action='DESELECT')
        bpy.ops.object.mode_set(mode='PAINT_GPENCIL')
        
        self.report({'INFO'}, "Randomized Line Art")
        return {'FINISHED'}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

B issueB-class issues indicate a functionality-related problem that does not fully stop use.SpicyHigh severity issues that affect use within the scope of its class.more info neededMore information surrounding the circumstances of issue or environment is neededmore testing neededThis issue needs more people to test its parameters, scope or repeatability.

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions