Source code for cam.operators.bas_relief_ops

"""Fabex 'basrelief.py'

Module to allow the creation of reliefs from Images or View Layers.
(https://en.wikipedia.org/wiki/Relief#Bas-relief_or_low_relief)
"""

import time

import numpy

import bpy

from bpy.types import Operator
from bpy.props import (
    BoolProperty,
    EnumProperty,
    FloatProperty,
    IntProperty,
    PointerProperty,
    StringProperty,
)

from ..constants import PRECISION

from ..bas_relief import (
    problem_areas,
    render_scene,
    relief,
    ReliefError,
)


[docs] class DoBasRelief(Operator): """Calculate Bas Relief"""
[docs] bl_idname = "scene.calculate_bas_relief"
[docs] bl_label = "Calculate Bas Relief"
[docs] bl_options = {"REGISTER", "UNDO"}
[docs] processes = []
# Bas Relief Properties
[docs] use_image_source: BoolProperty( name="Use Image Source", description="", default=False, )
[docs] source_image_name: StringProperty( name="Image Source", description="image source", )
[docs] view_layer_name: StringProperty( name="View Layer Source", description="Make a bas-relief from whatever is on this view layer", )
[docs] bit_diameter: FloatProperty( name="Diameter of Ball End in mm", description="Diameter of bit which will be used for carving", min=0.01, max=50.0, default=3.175, precision=PRECISION, )
[docs] pass_per_radius: IntProperty( name="Passes per Radius", description="Amount of passes per radius\n(more passes, " "more mesh precision)", default=2, min=1, max=10, )
[docs] width_mm: IntProperty( name="Desired Width in mm", default=200, min=5, max=4000, )
[docs] height_mm: IntProperty( name="Desired Height in mm", default=150, min=5, max=4000, )
[docs] thickness_mm: IntProperty( name="Thickness in mm", default=15, min=5, max=100, )
[docs] justify_x: EnumProperty( name="X", items=[ ("1", "Left", "", 0), ("-0.5", "Centered", "", 1), ("-1", "Right", "", 2), ], default="-1", )
[docs] justify_y: EnumProperty( name="Y", items=[ ("1", "Bottom", "", 0), ("-0.5", "Centered", "", 2), ("-1", "Top", "", 1), ], default="-1", )
[docs] justify_z: EnumProperty( name="Z", items=[ ("-1", "Below 0", "", 0), ("-0.5", "Centered", "", 2), ("1", "Above 0", "", 1), ], default="-1", )
[docs] depth_exponent: FloatProperty( name="Depth Exponent", description="Initial depth map is taken to this power. Higher = sharper relief", min=0.5, max=10.0, default=1.0, precision=PRECISION, )
[docs] silhouette_threshold: FloatProperty( name="Silhouette Threshold", description="Silhouette threshold", min=0.000001, max=1.0, default=0.003, precision=PRECISION, )
[docs] recover_silhouettes: BoolProperty( name="Recover Silhouettes", description="", default=True, )
[docs] silhouette_scale: FloatProperty( name="Silhouette Scale", description="Silhouette scale", min=0.000001, max=5.0, default=0.3, precision=PRECISION, )
[docs] silhouette_exponent: IntProperty( name="Silhouette Square Exponent", description="If lower, true depth distances between objects will be " "more visibe in the relief", default=3, min=0, max=5, )
[docs] attenuation: FloatProperty( name="Gradient Attenuation", description="Gradient attenuation", min=0.000001, max=100.0, default=1.0, precision=PRECISION, )
[docs] min_gridsize: IntProperty( name="Minimum Grid Size", default=16, min=2, max=512, )
[docs] smooth_iterations: IntProperty( name="Smooth Iterations", default=1, min=1, max=64, )
[docs] vcycle_iterations: IntProperty( name="V-Cycle Iterations", description="Set higher for planar constraint", default=2, min=1, max=128, )
[docs] linbcg_iterations: IntProperty( name="LINBCG Iterations", description="Set lower for flatter relief, and when using planar constraint", default=5, min=1, max=64, )
[docs] use_planar: BoolProperty( name="Use Planar Constraint", description="", default=False, )
[docs] gradient_scaling_mask_use: BoolProperty( name="Scale Gradients with Mask", description="", default=False, )
[docs] decimate_ratio: FloatProperty( name="Decimate Ratio", description="Simplify the mesh using the Decimate modifier. " "The lower the value the more simplyfied", min=0.01, max=1.0, default=0.1, precision=PRECISION, )
[docs] gradient_scaling_mask_name: StringProperty( name="Scaling Mask Name", description="Mask name", )
[docs] scale_down_before_use: BoolProperty( name="Scale Down Image Before Processing", description="", default=False, )
[docs] scale_down_before: FloatProperty( name="Image Scale", description="Image scale", min=0.025, max=1.0, default=0.5, precision=PRECISION, )
[docs] detail_enhancement_use: BoolProperty( name="Enhance Details", description="Enhance details by frequency analysis", default=False, )
# detail_enhancement_freq=FloatProperty(name="frequency limit", description="Image scale", min=0.025, max=1.0, default=.5, precision=PRECISION)
[docs] detail_enhancement_amount: FloatProperty( name="Amount", description="Image scale", min=0.025, max=1.0, default=0.5, precision=PRECISION, )
[docs] advanced: BoolProperty( name="Advanced Options", description="Show advanced options", default=True, )
[docs] def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self)
[docs] def execute(self, context): """Execute the relief rendering process based on the provided context. This function retrieves the scene and its associated bas relief settings. It checks if an image source is being used and sets the view layer name accordingly. The function then attempts to render the scene and generate the relief. If any errors occur during these processes, they are reported, and the operation is canceled. Args: context: The context in which the function is executed. Returns: dict: A dictionary indicating the result of the operation, either """ if not self.use_image_source and self.view_layer_name == "": self.view_layer_name = bpy.context.view_layer.name try: render_scene( self.width_mm, self.height_mm, self.bit_diameter, self.pass_per_radius, not self.use_image_source, self.view_layer_name, ) except ReliefError as e: self.report({"ERROR"}, str(e)) return {"CANCELLED"} except RuntimeError as e: self.report({"ERROR"}, str(e)) return {"CANCELLED"} try: relief(self) except ReliefError as e: self.report({"ERROR"}, str(e)) return {"CANCELLED"} return {"FINISHED"}
[docs] def draw(self, context): """Draw the user interface for the bas relief settings. This method constructs the layout for the bas relief settings in the Blender user interface. It includes various properties and options that allow users to configure the bas relief calculations, such as selecting images, adjusting parameters, and setting justification options. The layout is dynamically updated based on user selections, providing a comprehensive interface for manipulating bas relief settings. Args: context (bpy.context): The context in which the UI is being drawn. Returns: None: This method does not return any value; it modifies the layout directly. """ layout = self.layout layout.use_property_split = True layout.use_property_decorate = False scene = context.scene box = layout.box() col = box.column(align=True) col.label(text="Source") if self.use_image_source: col.prop_search(self, "source_image_name", bpy.data, "images") else: col.prop_search(self, "view_layer_name", context.scene, "view_layers") col.prop(self, "use_image_source") col.prop(self, "depth_exponent") col.prop(self, "advanced") box = layout.box() col = box.column(align=True) col.label(text="Parameters") col.prop(self, "bit_diameter", text="Ball End Diameter (mm)") col.prop(self, "pass_per_radius") col.prop(self, "widthmm", text="Desired Width (mm)") col.prop(self, "heightmm", text="Desired Height (mm)") col.prop(self, "thicknessmm", text="Thickness (mm)") box = layout.box() col = box.column(align=True) col.label(text="Justification") col.prop(self, "justifyx") col.prop(self, "justifyy") col.prop(self, "justifyz") box = layout.box() col = box.column(align=True) col.label(text="Silhouette") col.prop(self, "silhouette_threshold", text="Threshold") col.prop(self, "recover_silhouettes") if self.recover_silhouettes: col.prop(self, "silhouette_scale", text="Scale") if self.advanced: col.prop(self, "silhouette_exponent", text="Square Exponent") box = layout.box() col = box.column(align=True) col.label(text="Iterations") if self.advanced: col.prop(self, "smooth_iterations", text="Smooth") col.prop(self, "vcycle_iterations", text="V-Cycle") col.prop(self, "linbcg_iterations", text="LINBCG") if self.advanced: layout.prop(self, "min_gridsize") layout.prop(self, "decimate_ratio") layout.prop(self, "use_planar") layout.prop(self, "gradient_scaling_mask_use") if self.advanced: if self.gradient_scaling_mask_use: layout.prop_search(self, "gradient_scaling_mask_name", bpy.data, "images") layout.prop(self, "detail_enhancement_use") if self.detail_enhancement_use: layout.prop(self, "detail_enhancement_amount")
[docs] class ProblemAreas(Operator): """Find Bas Relief Problem Areas"""
[docs] bl_idname = "scene.problemareas_bas_relief"
[docs] bl_label = "Problem Areas Bas Relief"
[docs] bl_options = {"REGISTER", "UNDO"}
[docs] processes = []
# @classmethod # def poll(cls, context): # return context.active_object is not None
[docs] def execute(self, context): """Execute the operation related to the bas relief settings in the current scene. This method retrieves the current scene from the Blender context and accesses the bas relief settings. It then calls the `problemAreas` function to perform operations related to those settings. The method concludes by returning a status indicating that the operation has finished successfully. Args: context (bpy.context): The current Blender context, which provides access Returns: dict: A dictionary with a status key indicating the operation result, specifically {'FINISHED'}. """ s = bpy.context.scene br = s.basreliefsettings problem_areas(br) return {"FINISHED"}