import bpy
import math
from bpy.types import Panel, PropertyGroup, UIList, Operator
from bpy.props import (BoolProperty, EnumProperty, FloatProperty,
CollectionProperty, IntProperty, StringProperty,
PointerProperty)
from . ui_panel import ILSPpanel
from . thumbProcess import ThumbProcess
from . imageSpot import ImageSpot
########################################################################
# PROPERTIES
########################################################################
[docs]
class SpotProperties(PropertyGroup):
[docs]
def setDefaultValues(self, context):
pass
[docs]
def check(self, context):
return True
[docs]
class Profile(PropertyGroup):
radius: FloatProperty(
name="Radius",
description="Radius",
default=0.0,
min=0,
step=10,
update=lambda self, context: context.scene.ilsp_beam.updateLaserBeam(context),
) # type: ignore
value: FloatProperty(
name="Value",
description="Value",
default=1.0,
min=0,
max=1,
step=10,
) # type: ignore
profile: CollectionProperty(type=Profile) # type: ignore
profile_idx: IntProperty(
name="Index of spot profile",
default=0,
min=0
) # type: ignore
shape: EnumProperty(
name="Laser Spot Shape",
description="Laser Spot Shape",
items=(
('image', "Image Data", ""),
('circle', "Circular Laser Spot", ""),
('square', "Square Laser Spot", ""),
),
default='image',
) # type: ignore
consider_face_normal: BoolProperty(
name="Consider Face Normal",
description="Consider Face Normal",
default=True,
) # type: ignore
pure_square_radius: FloatProperty(
name="Pure Square Radius",
description="Pure Square Radius",
default=0.5,
min=0,
step=10,
) # type: ignore
[docs]
def show_image_in_new_window(self, image):
new_window = bpy.ops.screen.area_dupli('INVOKE_DEFAULT')
bpy.context.window_manager.windows[-1].screen.areas[-1].type = 'IMAGE_EDITOR'
# Get the latest window and its screen areas
new_screen = bpy.context.window_manager.windows[-1].screen
image_editor_area = None
# Find the IMAGE_EDITOR area
for area in new_screen.areas:
if area.type == 'IMAGE_EDITOR':
image_editor_area = area
break
if image_editor_area:
# Override context for the IMAGE_EDITOR area
override = bpy.context.copy()
override['area'] = image_editor_area
override['region'] = image_editor_area.regions[-1]
# Set the image to be displayed in the IMAGE_EDITOR area
with bpy.context.temp_override(**override):
bpy.ops.image.open(filepath=image.filepath)
bpy.data.screens[new_screen.name].areas[-1].spaces[0].image = image
else:
print("Could not find IMAGE_EDITOR area.")
[docs]
def readImageFile(self, context):
path = self.image_file_path
for image in bpy.data.images:
if image.name not in ['spot', 'colorBar']:
bpy.data.images.remove(image)
try:
img = bpy.data.images.get('spot')
img.filepath = path
img.reload()
except Exception:
img = bpy.data.images.load(path, check_existing=True)
img.name = 'spot'
try:
texture = bpy.data.textures["spot"]
except Exception:
texture = bpy.data.textures.new(name="spot", type="IMAGE")
texture.image = img
texture.extension = 'CLIP'
self.show_image_in_new_window(img)
image_file_path: StringProperty(
name="",
description="Image File Path",
default="",
maxlen=1024,
subtype='FILE_PATH',
update=lambda self, context: self.readImageFile(context)
) # type: ignore
[docs]
def readColorBarFile(self, context):
path = self.color_bar_file_path
for image in bpy.data.images:
if image.name not in ['spot', 'colorBar']:
bpy.data.images.remove(image)
try:
img = bpy.data.images.get('colorBar')
img.filepath = path
img.reload()
except Exception:
img = bpy.data.images.load(path, check_existing=True)
img.name = 'colorBar'
try:
texture = bpy.data.textures["colorBar"]
except Exception:
texture = bpy.data.textures.new(name="colorBar", type="IMAGE")
texture.image = img
texture.extension = 'CLIP'
self.show_image_in_new_window(img)
color_bar_file_path: StringProperty(
name="",
description="Color Bar File Path",
default="",
maxlen=1024,
subtype='FILE_PATH',
update=lambda self, context: self.readColorBarFile(context)
) # type: ignore
first_treshold: FloatProperty(
name="Bottom/Left Value",
description="Color Bar Bottom/Left Value",
default=0,
) # type: ignore
second_treshold: FloatProperty(
name="Top/Right Value",
description="Color Bar Top/Right Value",
default=1.0,
) # type: ignore
spot_size: FloatProperty(
name="Spot Size",
description="Spot Size",
default=0.5,
min=0,
step=10,
) # type: ignore
########################################################################
# PANELS
########################################################################
[docs]
class ILSP_PT_spot(ILSPpanel, Panel):
bl_label = "Laser Spot"
[docs]
@classmethod
def poll(cls, context):
return True
[docs]
def draw(self, context):
layout = self.layout
layout.use_property_split = False
layout.use_property_decorate = False
spot = context.scene.ilsp_spot
row = layout.row(align=True)
row.prop(spot, 'consider_face_normal')
row = layout.row(align=True)
row.prop_enum(spot, "shape", 'image',
text='Image Data')
col = row.column()
col.prop_enum(spot, "shape", 'square',
text='Square Laser Spot')
col = row.column()
col.prop_enum(spot, "shape", 'circle',
text='Circular Laser Spot')
if spot.shape == 'square' or spot.shape == 'circle':
layout.template_list("ILSP_UL_spot_profile",
"The_List",
spot, "profile",
spot, "profile_idx")
layout.operator('ilsp_spot_profile.new_item',
text='ADD', icon='ADD')
layout.separator()
if spot.shape == 'square':
row = layout.row(align=True)
row.prop(spot, 'pure_square_radius')
if spot.shape == 'image':
layout.prop(spot, "image_file_path", text="Image File Path")
row = layout.row(align=True)
row.prop(spot, 'spot_size')
layout.prop(spot, "color_bar_file_path", text="Color Bar File Path")
grid = layout.grid_flow(columns=2, align=True)
grid.prop(spot, 'first_treshold')
grid.prop(spot, 'second_treshold')
col = self.layout.box().column()
texture = bpy.data.textures.get('spot')
if texture is not None:
#col.template_preview(texture, show_buttons=True)
row = layout.row()
row.template_ID_preview(texture, 'image', open="image_user.open", hide_buttons=True, filter='AVAILABLE')
row.scale_y = 2.0
status = spot.check(context)
try:
len(status)
except Exception:
return
layout.label(text=status[1], icon_value=status[2])
[docs]
class ILSP_UL_spot_profile(UIList):
[docs]
def draw_item(self, context, layout, data, item, icon, active_data,
active_propname, index):
grid = layout.grid_flow(columns=3, align=True)
grid.prop(item, 'radius')
grid.prop(item, 'value', slider=True)
op = grid.operator('ilsp_spot_profile.delete_item',
text='', icon='X')
op.index = index
[docs]
class ILSP_OT_spot_profile_ADD(Operator):
bl_idname = "ilsp_spot_profile.new_item"
bl_label = "Add"
[docs]
def execute(self, context):
profile = context.scene.ilsp_spot.profile
item = profile.add()
item.radius = 0.0
item.value = 1.0
return {'FINISHED'}
[docs]
class ILSP_OT_spot_profile_DELETE(Operator):
bl_idname = "ilsp_spot_profile.delete_item"
bl_label = "Delete"
index: IntProperty()
[docs]
@classmethod
def poll(cls, context):
return True
[docs]
def execute(self, context):
context.scene.ilsp_spot.spot_profile.remove(self.index)
return {'FINISHED'}
[docs]
class ILSP_OT_spot_profile_view_thumbnail(Operator):
bl_idname = "ilsp_spot_profile.view_thumbnail"
bl_label = ""
bl_description = "View larger thumbnail"
bl_options = {"INTERNAL"}
[docs]
def execute(self, context):
thumbProcess = ThumbProcess(context)
thumbProcess.simulate(context)
return {'FINISHED'}