Source code for liatool.ui_process

from os import getcwd, path
from bpy.app.handlers import persistent
import math
import bpy
import random
from mathutils import Vector
from bpy.types import Panel, PropertyGroup, Operator, UIList
from bpy.props import (BoolProperty, EnumProperty, PointerProperty, IntProperty,
                       FloatProperty, CollectionProperty, StringProperty, FloatVectorProperty)
from . ui_panel import ILSPpanel
from . import utils
from . import laserBeam as lb
from . import userProcess as userProc
from . import illumination as illum
from . import robotInstructions as robot
from . imageSpot import ColorBar


########################################################################
# PROPERTIES
########################################################################
[docs] class ProcessProperties(PropertyGroup):
[docs] def setDefaultValues(self, context): pass
[docs] def check(self, context): if self.selected_domain is None: message = 'none iLSP domain selected ...' iconValue = 3 return False, message, iconValue return True
def _selectedDomainPoll(self, object): return utils.getDomainByDomainObj(object) selected_domain: PointerProperty( name="Selected Domain", description="Selected Domain", type=bpy.types.Object, poll=lambda self, object: self._selectedDomainPoll(object), )
[docs] def setPivotPointToSelected(self, context): obj = self.selected_domain cursor = bpy.context.scene.cursor.location obj.location = cursor obj.rotation_euler = (0.0, 0.0, 0.0) bpy.ops.view3d.snap_cursor_to_selected() cursor = bpy.context.scene.cursor.location utils.selectOnlyObj(obj) bpy.ops.object.origin_set(type='ORIGIN_CURSOR') self.pivot_point = cursor
set_pivot_point_selected: BoolProperty( name="Set Pivot Point To Selected", description="Set Pivot Point To Selected", update=lambda self, context: self.setPivotPointToSelected(context), default=False, ) # type: ignore
[docs] def setPivotPoint(self, context): obj = self.selected_domain cursor = bpy.context.scene.cursor.location obj.location = cursor obj.rotation_euler = (0.0, 0.0, 0.0) cursor[0] = self.pivot_point[0] cursor[1] = self.pivot_point[1] cursor[2] = self.pivot_point[2] utils.selectOnlyObj(obj) bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
pivot_point: FloatVectorProperty( name="Pivot Point", description="Pivot Point", unit='LENGTH', default=(0.0, 0.0, 0.0), size=3, update=lambda self, context: self.setPivotPoint(context), ) # type: ignore
[docs] class UserProcess(PropertyGroup): rx: FloatProperty( name="rx", description="Rotation Increment Around x-axis [deg]", default=0.0, step=10, ) ry: FloatProperty( name="ry", description="Rotation Increment Around y-axis [deg]", default=0.0, step=10, ) rz: FloatProperty( name="rz", description="Rotation Increment Around z-axis [deg]", default=0.0, step=10, ) dx: FloatProperty( name="dx", description="Displacement Increment x-axis Direction", default=0.0, step=10, ) dy: FloatProperty( name="dy", description="Displacement Increment y-axis Direction", default=0.0, step=10, ) dz: FloatProperty( name="dz", description="Displacement Increment z-axis Direction", default=0.0, step=10, ) velocity: FloatProperty( name="v", description="Velocity", default=1.0, step=10, ) frequency: FloatProperty( name="f", description="Frequency [Hz]", default=1.0, step=10, )
user_process: CollectionProperty(type=UserProcess) user_process_idx: IntProperty( name="Index of user process", default=0, min=0, ) simulation_type: EnumProperty( name='', description="Simulation Type", items=[('SUMMATION', 'SUMMATION', ''), ('MAXIMUM', 'MAXIMUM', '')] )
[docs] def readRobotInstructionFile(self, context): if self.robot_file_path_import == '': return robotInstructions = robot.RobotInstructions(self.robot_file_path_import) robotInstructions.importInstructions() instructions = robotInstructions.instructions user_process = context.scene.ilsp_process.user_process user_process.clear() for idx in range(0, len(instructions)): item = user_process.add() prevPosition = robot.Position() if idx > 0: prevPosition = instructions[idx - 1].position item.dx = 0.0 item.dy = 0.0 item.dz = 0.0 item.rx = 0.0 item.ry = 0.0 item.rz = 0.0 item.velocity = 0.0 item.frequency = 0.0 instruction = instructions[idx] if instruction.velocity > 0.0: position = instruction.position item.dx = position.x - prevPosition.x item.dy = position.y - prevPosition.y item.dz = position.z - prevPosition.z item.rx = position.rx - prevPosition.rx item.ry = position.ry - prevPosition.ry item.rz = position.rz - prevPosition.rz item.velocity = instruction.velocity item.frequency = instruction.frequency
[docs] def exportRobotInstructionFile(self, context): if self.robot_file_path_export == '': return if path.exists(self.robot_file_path_export): return robotInstructions = robot.RobotInstructions(self.robot_file_path_export) robotInstructions.exportInstructions(context.scene.ilsp_process.user_process)
# instructions = robot.RobotInstructions(self.robot_file_path_import).instructions # user_process = context.scene.ilsp_process.user_process # user_process.clear() # for idx in range(0, len(instructions)): # item = user_process.add() # prevPosition = robot.Position() # if idx > 0: # prevPosition = instructions[idx - 1].position # item.dx = 0.0 # item.dy = 0.0 # item.dz = 0.0 # item.rx = 0.0 # item.ry = 0.0 # item.rz = 0.0 # item.velocity = 0.0 # item.frequency = 0.0 # instruction = instructions[idx] # if instruction.velocity > 0.0: # position = instruction.position # item.dx = position.x - prevPosition.x # item.dy = position.y - prevPosition.y # item.dz = position.z - prevPosition.z # item.rx = position.rx - prevPosition.rx # item.ry = position.ry - prevPosition.ry # item.rz = position.rz - prevPosition.rz # item.velocity = instruction.velocity # item.frequency = instruction.frequency robot_file_path_import: StringProperty( name="", description="Import Robot Instructions File Path", default="", maxlen=1024, subtype='FILE_PATH', update=lambda self, context: self.readRobotInstructionFile(context)) robot_file_path_export: StringProperty( name="", description="Export Robot Instructions File Path", default="", maxlen=1024, subtype='FILE_PATH', update=lambda self, context: self.exportRobotInstructionFile(context))
[docs] def setMinTreshold(self, context): if self.auto_tresholds: if self.min_treshold < self.min_treshold_min: self.min_treshold = self.min_treshold_min min = self.min_treshold max = self.max_treshold if max < min: self.max_treshold = min domainObj = context.scene.ilsp_process.selected_domain colorRamp = domainObj.data.materials[0].node_tree.nodes['Color Ramp'] multiply = domainObj.data.materials[0].node_tree.nodes['Multiply'] add = domainObj.data.materials[0].node_tree.nodes['Add'] a = 1.0 / (self.max_treshold_max - self.min_treshold_min) b = self.min_treshold_min / (self.min_treshold_min - self.max_treshold_max) multiply.inputs[1].default_value = a add.inputs[1].default_value = b unitMin = a * min + b unitMax = a * max + b colorRamp.color_ramp.elements[0].position = 0 colorRamp.color_ramp.elements[1].position = unitMin colorRamp.color_ramp.elements[2].position = unitMin colorRamp.color_ramp.elements[3].position = 0.5 * (unitMin + unitMax) colorRamp.color_ramp.elements[4].position = unitMax colorRamp.color_ramp.elements[5].position = unitMax
# colorBar = ColorBar() # for i in range(1, len(colorRamp.color_ramp.elements) - 2): # elem = colorRamp.color_ramp.elements[i] # position = elem.position # if position < min: # c = (0.8, 0.8, 0.8, 1) # else: # try: # c = colorBar._data[i - 1][1] # except Exception: # pass # elem.color = c min_treshold: FloatProperty( name="minimal treshold", description="minimal treshold", default=0.0, step=10, update=lambda self, context: self.setMinTreshold(context), ) min_treshold_min: FloatProperty( name="minimal treshold min", description="minimal treshold min", default=0.0, step=10 ) max_treshold: FloatProperty( name="maximal treshold", description="maximal treshold", default=1.0, step=10, update=lambda self, context: self.setMaxTreshold(context), ) max_treshold_max: FloatProperty( name="maximal treshold max", description="maximal treshold max", default=1.0, step=10 )
[docs] def setTresholds(self, context): self._updateSimulation(context) self.setMinTreshold(context) self.setMaxTreshold(context)
auto_tresholds: BoolProperty( name="automatic tresholds", description="automatic tresholds", default=True, update=lambda self, context: self.setTresholds(context), )
[docs] def setMaxTreshold(self, context): if self.auto_tresholds: if self.max_treshold > self.max_treshold_max: self.max_treshold = self.max_treshold_max min = self.min_treshold max = self.max_treshold if max < min: self.min_treshold = max domainObj = context.scene.ilsp_process.selected_domain colorRamp = domainObj.data.materials[0].node_tree.nodes['Color Ramp'] a = 1.0 / (self.max_treshold_max - self.min_treshold_min) b = self.min_treshold_min / (self.min_treshold_min - self.max_treshold_max) unitMin = a * min + b unitMax = a * max + b colorRamp.color_ramp.elements[0].position = 0 colorRamp.color_ramp.elements[1].position = unitMin colorRamp.color_ramp.elements[2].position = unitMin colorRamp.color_ramp.elements[3].position = 0.5 * (unitMin + unitMax) colorRamp.color_ramp.elements[4].position = unitMax colorRamp.color_ramp.elements[5].position = unitMax
# for i in range(1, len(colorRamp.color_ramp.elements) - 2): # elem = colorRamp.color_ramp.elements[i] # position = elem.position # if position > max: # c = (0.8, 0.8, 0.8, 1) # else: # try: # c = colorBar._data[i - 1][1] # except Exception: # pass # elem.color = c
[docs] class Material(PropertyGroup): material: bpy.props.PointerProperty(type=bpy.types.Material)
materials: CollectionProperty(type=Material) def _updateSimulation(self, context): domainObj = self.selected_domain if domainObj.data.materials: domainObj.data.materials[0] = self.materials[self.material_idx].material frame = bpy.context.scene.frame_current domainObj = bpy.context.scene.ilsp_process.selected_domain illumination = domainObj.data.materials[0] illumination.node_tree.nodes["Attribute"].attribute_name =\ illumination.name + '_' + str(frame) name = illumination.node_tree.nodes["Attribute"].attribute_name min = float('inf') max = -float('inf') if self.auto_tresholds: values = domainObj.data.attributes.get(name) if values is not None: for polygon in domainObj.data.polygons: value = values.data[polygon.index].value if value > max: max = value if value < min: min = value self.min_treshold_min = min self.max_treshold_max = max self.min_treshold = min self.max_treshold = max material_idx: IntProperty( name="Index of material", default=0, min=0, update=lambda self, context: self._updateSimulation(context) ) start_line: IntProperty( name="Start Line Number", default=1, min=1, ) end_line: IntProperty( name="End Line Number", default=1, min=1, ) no_repeats: IntProperty( name="Number of Repeats", default=1, min=1, )
######################################################################## # PANELs ########################################################################
[docs] class ILSP_PT_process(ILSPpanel, Panel): bl_label = "Process Prescription"
[docs] @classmethod def poll(cls, context): return utils.domainsExists()
def _enabled(self, context): if context.scene.ilsp_process.selected_domain is None: return False else: return True
[docs] def draw(self, context): layout = self.layout layout.use_property_split = False layout.use_property_decorate = False process = context.scene.ilsp_process enabled = self._enabled(context) row = layout.row() row.enabled = True row.prop(process, "selected_domain", icon='OUTLINER_OB_MESH') row = layout.row(align=True) row.enabled = enabled row.prop(process, 'pivot_point') col = row.column() col.prop(process, "set_pivot_point_selected", icon='RESTRICT_SELECT_OFF', icon_only=True, emboss=False) layout.separator() layout.label(text="Robot Instructions:") grid = layout.grid_flow(columns=2, align=True) grid.prop(process, "robot_file_path_import", text="Import", icon='IMPORT') grid.prop(process, "robot_file_path_export", text="Export", icon='EXPORT') layout.template_list("ILSP_UL_user_process", "The_List", process, "user_process", process, "user_process_idx") layout.operator('ilsp_user_process.new_item', text='ADD LINE', icon='ADD') grid = layout.grid_flow(columns=4, align=True) grid.prop(process, 'start_line', text='Start Line') grid.prop(process, 'end_line', text='End Line') grid.prop(process, 'no_repeats', text='Repetitions') grid.operator('ilsp_user_process.copy', text='ADD REPEATING BLOCK', icon='DECORATE_OVERRIDE') grid = layout.grid_flow(columns=2, align=True) layout.operator('ilsp_user_process.clear', text='CLEAR', icon='TRASH') layout.separator() row = layout.row() row.enabled = enabled row.prop(process, 'simulation_type') row.operator("process.simulate", text="Simulate Illumination") layout.separator() layout.label(text="Results") domainObj = context.scene.ilsp_process.selected_domain colorRamp = domainObj.data.materials[0].node_tree.nodes['Color Ramp'] layout.template_color_ramp(colorRamp, "color_ramp", expand=True) grid = layout.grid_flow(columns=2, align=True) grid.enabled = enabled grid.prop(process, 'min_treshold', slider=True) grid.prop(process, 'max_treshold', slider=True) layout.prop(process, 'auto_tresholds') domainObj = process.selected_domain layout.template_list("ILSP_UL_materials", "The_List", process, "materials", process, "material_idx") status = process.check(context) try: len(status) except Exception: return layout.label(text=status[1], icon_value=status[2])
######################################################################## # OPERATORS ########################################################################
[docs] class ILSP_UL_user_process(UIList):
[docs] def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): grid = layout.grid_flow(columns=10, align=True) grid.label(text=str(index + 1)) grid.prop(item, 'dx') grid.prop(item, 'dy') grid.prop(item, 'dz') grid.prop(item, 'rx') grid.prop(item, 'ry') grid.prop(item, 'rz') grid.prop(item, 'velocity') grid.prop(item, 'frequency') op = grid.operator('ilsp_user_process.delete_item', text='', icon='X') op.index = index
[docs] class ILSP_UL_materials(UIList):
[docs] def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): layout.prop(item, "name", text="", emboss=False, icon_value=icon)
[docs] class ILSP_OT_user_process_ADD(Operator): bl_idname = "ilsp_user_process.new_item" bl_label = "Add"
[docs] def execute(self, context): user_process = context.scene.ilsp_process.user_process item = user_process.add() if len(user_process) > 1: item.dx = user_process[-2].dx item.dy = user_process[-2].dy item.dz = user_process[-2].dz item.rx = user_process[-2].rx item.ry = user_process[-2].ry item.rz = user_process[-2].rz item.velocity = user_process[-2].velocity item.frequency = user_process[-2].frequency return {'FINISHED'}
[docs] class ILSP_OT_user_process_COPY(Operator): bl_idname = "ilsp_user_process.copy" bl_label = "DO"
[docs] def execute(self, context): process = context.scene.ilsp_process user_process = process.user_process startIdx = process.start_line - 1 endIdx = process.end_line - 1 noRepeats = process.no_repeats for repeat in range(0, noRepeats): for itemIdx in range(startIdx, endIdx + 1): item = user_process.add() item.dx = user_process[itemIdx].dx item.dy = user_process[itemIdx].dy item.dz = user_process[itemIdx].dz item.rx = user_process[itemIdx].rx item.ry = user_process[itemIdx].ry item.rz = user_process[itemIdx].rz item.velocity = user_process[itemIdx].velocity item.frequency = user_process[itemIdx].frequency return {'FINISHED'}
[docs] class ILSP_OT_user_process_CLEAR(Operator): bl_idname = "ilsp_user_process.clear" bl_label = "Clear"
[docs] def execute(self, context): user_process = context.scene.ilsp_process.user_process user_process.clear() return {'FINISHED'}
[docs] class ILSP_OT_user_process_DELETE(Operator): bl_idname = "ilsp_user_process.delete_item" bl_label = "Delete" index: IntProperty()
[docs] @classmethod def poll(cls, context): return True
[docs] def execute(self, context): context.scene.ilsp_process.user_process.remove(self.index) return {'FINISHED'}
[docs] class ILSP_OT_process_simulate(Operator): bl_idname = "process.simulate" bl_label = "3D-Print Info Volume" bl_description = "Report the volume of the active mesh"
[docs] @classmethod def poll(cls, context): status = context.scene.ilsp_process.check(context) try: len(status) except Exception: return True return False
[docs] def execute(self, context): ui_laserSpot = context.scene.ilsp_spot ui_laserBeam = context.scene.ilsp_beam ui_process = context.scene.ilsp_process ui_laserBeam.show_beam = False ui_laserBeam.deleteLaserBeam(context) domainObj = ui_process.selected_domain process = userProc.UserProcess( ilspDomain=domainObj, processSteps=ui_process.user_process) laserBeam = lb.LaserBeam(laserSpot=ui_laserSpot, laserBeam=ui_laserBeam) utils.selectOnlyObj(domainObj) illumination = illum.Illumination(process=process, spaceProfile=laserBeam.spaceProfil) min, max = illumination.simulate(laserBeam=laserBeam) domainObj = context.scene.ilsp_process.selected_domain ui_process.min_treshold = min ui_process.min_treshold_min = min ui_process.max_treshold = max ui_process.max_treshold_max = max ui_process.materials.clear() idx = -1 for material in bpy.data.materials: if domainObj.name in material.name: item = ui_process.materials.add() item.material = material item.name = material.name.removeprefix(domainObj.name + '_illumination_') item.name = 'Simulation ' + item.name idx += 1 if idx <= 0: idx = 0 ui_process.material_idx = idx return {'FINISHED'}
[docs] @persistent def my_handler(scene, context): frame = scene.frame_current domainObj = scene.ilsp_process.selected_domain illumination = domainObj.data.materials[0] illumination.node_tree.nodes["Attribute"].attribute_name =\ illumination.name + '_' + str(frame) scene.ilsp_process._updateSimulation(context)
bpy.app.handlers.frame_change_pre.append(my_handler)