jumeaux-numeriques/twin.py

773 lines
28 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import bge # Blender Game Engine (UPBGE)
import bpy # Blender
import os
import sys
import importlib
import subprocess # Multiprocessus
import math
import time
import xml.etree.ElementTree as ET # Creating/parsing XML file
import runpy # Exécution de script Python légère (sans import)
from pylint import epylint as lint # Mesure de la qualité d'un code Python
import twin_doc # Documentation
import twin_about # About
###############################################################################
# twin.py
# @title: Bibliothèque générale de l'environnement 3D pour le développement de jumeau numérique
# @project: Blender-EduTech
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2020-2023 Philippe Roy
# @license: GNU GPL
#
# Cet environnement 3D est programmable en Python. Il est destiné à la découverte de la programmation de système pluritechnologique.
#
###############################################################################
# UPBGE scene
scene = bge.logic.getCurrentScene()
eevee = bpy.context.scene.eevee
system=importlib.import_module(scene.objects['System']['system']) # Système
scene.objects['System']['script'] = os.path.join(os.getcwd(), scene.objects['System']['system']+"_cmd.py") # Script par défaut
# Memory
sys.setrecursionlimit(10**5) # Limite sur la récursivité (valeur par défaut : 1000) -> segfault de Blender
# Config file
twin_config = ET.parse('twin_config.xml').getroot()
# Couleurs
color_cmd = (0.8, 0.8, 0.8, 1) # Blanc
color_cmd_hl = (0.8, 0.619, 0.021, 1) # Jaune
color_passive = (0.800, 0.005, 0.315,1) # bouton non activable : magenta
color_active = (0.799, 0.130, 0.063,1) # bouton activable : orange
color_hl = (0.8, 0.8, 0.8, 1) # bouton focus : blanc
color_activated = (0.8, 0.619, 0.021, 1) # bouton activé numériquement uniquement : jaune
color_activated_real = (0.799, 0.031, 0.038, 1) # élément activé physiquement uniquement : rouge (hors clic)
color_activated_dbl = (0.246, 0.687, 0.078, 1) # élément activé physiquement et numériquement : vert clair
color_blue = (0.007, 0.111, 0.638, 1) # Couleur Blue (Actionneur type moteur)
color_blue_dark = (0.004, 0.054, 0.296, 1) # Couleur Blue (Actionneur type moteur)
color_grey = (0.285, 0.285, 0.285, 1) # Couleur Blue (Actionneur type moteur)
color_led_yellow = (0.799, 0.617, 0.021, 1) # Couleur Led Jaune
# Constantes
JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
JUST_RELEASED = bge.logic.KX_INPUT_JUST_RELEASED
ACTIVATE = bge.logic.KX_INPUT_ACTIVE
# JUST_DEACTIVATED = bge.logic.KX_SENSOR_JUST_DEACTIVATED
###############################################################################
# Gestion du clavier
###############################################################################
# Mode : Orbit(0) par défaut, Pan(1) avec Shift, Zoom (2) avec Ctrl, Eclaté (1) avec Shift
def keyboard(cont):
obj = scene.objects['System']
keyboard = bge.logic.keyboard
# Touche ESC
if JUST_ACTIVATED in keyboard.inputs[bge.events.ESCKEY].queue:
# Maj du fichier de config (screen size : data/config/screen/width-> [0][0].text)
screen_width = bge.render.getWindowWidth()
screen_height = bge.render.getWindowHeight()
twin_config[0][0].text=str(screen_width)
twin_config[0][1].text=str(screen_height)
twin_config[0][2].text=str(scene.objects['About']['quality'])
buffer_xml = ET.tostring(twin_config)
with open("twin_config.xml", "wb") as f:
f.write(buffer_xml)
# Sortir
bge.logic.endGame()
# Shift -> mode 1 : Pan (clic milieu) ou Eclaté (clic gauche)
if JUST_ACTIVATED in keyboard.inputs[bge.events.LEFTSHIFTKEY].queue:
obj['manip_mode']=1
if JUST_ACTIVATED in keyboard.inputs[bge.events.RIGHTSHIFTKEY].queue:
obj['manip_mode']=1
# Ctrl -> mode 2 : Zoom (clic milieu)
if JUST_ACTIVATED in keyboard.inputs[bge.events.LEFTCTRLKEY].queue:
obj['manip_mode']=2
if JUST_ACTIVATED in keyboard.inputs[bge.events.RIGHTCTRLKEY].queue:
obj['manip_mode']=2
# Pas de modificateur -> mode 0 : Orbit (clic milieu)
if JUST_RELEASED in keyboard.inputs[bge.events.LEFTSHIFTKEY].queue:
obj['manip_mode']=0
if JUST_RELEASED in keyboard.inputs[bge.events.RIGHTSHIFTKEY].queue:
obj['manip_mode']=0
if JUST_RELEASED in keyboard.inputs[bge.events.LEFTCTRLKEY].queue:
obj['manip_mode']=0
if JUST_RELEASED in keyboard.inputs[bge.events.RIGHTCTRLKEY].queue:
obj['manip_mode']=0
# Touche Home -> Reset de la vue
if JUST_ACTIVATED in keyboard.inputs[bge.events.HOMEKEY].queue:
manip_reset()
# Touche F5 -> Run et Pause
if JUST_ACTIVATED in keyboard.inputs[bge.events.F5KEY].queue:
cycle_run ()
# Touche F6 -> Stop / Init
if JUST_ACTIVATED in keyboard.inputs[bge.events.F6KEY].queue:
cycle_stop ()
###############################################################################
# Commandes
###############################################################################
##
# Initialisation des commandes
##
def cmd_init():
# Fichier de config (screen size : data/config/screen/width-> [0][0].text, height-> [0][1].text)
bge.render.setWindowSize(int(twin_config[0][0].text),int(twin_config[0][1].text))
quality_eevee=('NOSMAA', 'LOW', 'MEDIUM','HIGH','ULTRA')
scene.objects['About']['quality'] = int(twin_config[0][2].text)
if quality_eevee[scene.objects['About']['quality']] == 'NOSMAA':
eevee.smaa_quality= 'LOW'
eevee.use_eevee_smaa = False
else:
eevee.use_eevee_smaa = True
eevee.smaa_quality= quality_eevee[scene.objects['About']['quality']]
# Ajout du Hud
# scene.active_camera = scene.objects["Camera"]
# scene.objects['Sun'].setVisible(True,True)
# scene.addOverlayCollection(scene.cameras['Camera-Hud'], bpy.data.collections['Hud'])
# UI : Commands
scene.objects['Run-Hl'].setVisible(False,False)
# scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Doc-cmd-Hl'].setVisible(False,False)
scene.objects['ResetView-Hl'].setVisible(False,False)
scene.objects['File-Hl'].setVisible(False,False)
scene.objects['About-cmd-Hl'].setVisible(False,False)
# UI : Text, ...
scene.objects['Cmd-text']['Text']=""
scene.objects['Cmd-text'].setVisible(True,False)
scene.objects['Script-text']['Text']=scene.objects['System']['script']
scene.objects['Twins-text']['Text']="Connection fermée."
# Windows
windows=("Doc", "Doc_chap-general", "Doc_chap-system", "Doc_chap-python", "About")
for window in windows:
scene.objects[window].setVisible(False,True)
# Jumeau
scene.objects['System']['twins'] = False
##
# Highlight des commandes
##
def cmd_hl(cont):
obj = cont.owner
# Activation
if cont.sensors['MO'].status == JUST_ACTIVATED and scene.objects['System']['manip_mode']==0:
if obj.name!="Run" and obj.name!="Pause" and obj.name!="Stop" and obj.name!="Doc-cmd-colbox":
# if obj.name!="Run" and obj.name!="Pause" and obj.name!="Run-Hl" and obj.name!="Pause-Hl" and obj.name!="Pause-Hl":
obj.setVisible(False,True)
scene.objects[obj.name+'-Hl'].setVisible(True,True)
# Run et pause
if obj.name=="Pause" or obj.name=="Run":
if scene.objects['System']['run'] == True:
pass
# scene.objects['Pause'].setVisible(False,False) FIXME pause pas implémenté
# scene.objects['Pause-Hl'].setVisible(True,False) FIXME pause pas implémenté
else:
scene.objects['Run'].setVisible(False,False)
scene.objects['Run-Hl'].setVisible(True,False)
# Stop
if obj.name=="Stop":
scene.objects['Stop'].setVisible(False,False)
scene.objects['Stop-Hl'].setVisible(True,False)
# Doc
if obj.name=="Doc-cmd-colbox":
scene.objects['Doc-cmd'].setVisible(False,False)
scene.objects['Doc-cmd-Hl'].setVisible(True,False)
# Text
text_hl ={"Run":"Exécuter (F5)",
"Stop":"Stop et initialisation (F6)",
# "Pause":"Pause (F5)",
"Doc-cmd-colbox":"Documentation",
"ResetView": "Reset de la vue (Touche Début)",
"File": "Changer le fichier de commandes",
"About-cmd": "A propos"}
scene.objects['Cmd-text']['modal']= False
scene.objects['Cmd-text']['Text']= text_hl[obj.name]
if scene.objects['Doc']['page_chap']== "" and obj.name =="Doc-cmd-colbox" :
scene.objects['Cmd-text']['Text']= "Chargement de la documentation ..."
if scene.objects['Doc']['page_chap']!= "" and obj.name =="Doc-cmd-colbox" :
bpy.context.view_layer.update() # Bug de mise à jour
scene.objects['Cmd-text'].setVisible(True,False)
# Désactivation
if cont.sensors['MO'].status == JUST_RELEASED and (scene.objects['System']['manip_mode']==0 or scene.objects['System']['manip_mode']==9):
if scene.objects['Cmd-text']['modal'] != True:
scene.objects['Cmd-text']['Text']= ""
scene.objects['Cmd-text'].setVisible(False,False)
if obj.name!="Run" and obj.name!="Pause" and obj.name!="Stop" and obj.name!="Doc-cmd-colbox":
scene.objects[obj.name+'-Hl'].setVisible(False,True)
obj.setVisible(True,True)
# Run et pause
if obj.name=="Pause" or obj.name=="Run":
if scene.objects['System']['run'] == True:
pass
# scene.objects['Pause-Hl'].setVisible(False,False) FIXME pause pas implémenté
# scene.objects['Pause'].setVisible(True,False) FIXME pause pas implémenté
else:
scene.objects['Run-Hl'].setVisible(False,False)
scene.objects['Run'].setVisible(True,False)
# Stop
if obj.name=="Stop":
scene.objects['Stop-Hl'].setVisible(False,False)
scene.objects['Stop'].setVisible(True,False)
# Doc
if obj.name=="Doc-cmd-colbox":
scene.objects['Doc-cmd-Hl'].setVisible(False,False)
scene.objects['Doc-cmd'].setVisible(True,False)
##
# Click sur les commandes
##
def cmd_click(cont):
obj = cont.owner
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['System']['manip_mode']==0:
# Play et pause
if obj.name=="Pause" or obj.name=="Run":
cycle_run ()
# Stop
if obj.name=="Stop":
cycle_stop ()
# Aide
if obj.name=="Doc-cmd-colbox" :
twin_doc.open()
# Reset-view
if obj.name=="ResetView" :
manip_reset()
# Fichier de commande
if obj.name=="File" :
file_open()
# About
if obj.name=="About-cmd" :
twin_about.open()
###############################################################################
# Manipulation du mécanisme
###############################################################################
##
# Dessiner une cercle (bas niveau)
##
def circle (center, radius, color):
ang = 0
ang_step = 0.1
while ang< 2 * math.pi:
x0 = center[0]+float(radius*math.cos(ang)*0.95)
y0 = center[1]
z0 = center[2]+float(radius*math.sin(ang))
x1 = center[0]+float(radius*math.cos(ang+ang_step)*0.95)
y1 = center[1]
z1 = center[2]+float(radius*math.sin(ang+ang_step))
bge.render.drawLine([x0,y0,z0],[x1,y1,z1],color)
ang += ang_step
##
# Initialisation de la vue 3D
##
# def manip_init(cont):
def manip_init():
# Ajout du Hud
scene.active_camera = scene.objects["Camera"]
scene.objects['Sun'].setVisible(True,True)
scene.addOverlayCollection(scene.cameras['Camera-Hud'], bpy.data.collections['Hud'])
# Fenêtres
scene.objects['About'].setVisible(False,True)
scene.objects['Doc'].setVisible(False,True)
# Mémorisation de la position de la caméra
scene.objects['Camera']['init_lx']=scene.objects['Camera'].worldPosition.x
scene.objects['Camera']['init_ly']=scene.objects['Camera'].worldPosition.y
scene.objects['Camera']['init_lz']=scene.objects['Camera'].worldPosition.z
# Mémorisation de la position du modèle
scene.objects['System']['init_lx']=scene.objects['System'].worldPosition.x
scene.objects['System']['init_ly']=scene.objects['System'].worldPosition.y
scene.objects['System']['init_lz']=scene.objects['System'].worldPosition.z
scene.objects['System']['init_rx']=scene.objects['System'].worldOrientation.to_euler().x
scene.objects['System']['init_ry']=scene.objects['System'].worldOrientation.to_euler().y
scene.objects['System']['init_rz']=scene.objects['System'].worldOrientation.to_euler().z
##
# Atteindre une orientation (bas niveau)
##
def applyRotationTo(obj, rx=None, ry=None, rz=None):
rres=0.001 # resolution rotation
# x
if rx is not None:
while (abs(rx-obj.worldOrientation.to_euler().x) > rres) :
if obj.worldOrientation.to_euler().x-rx > rres:
obj.applyRotation((-rres, 0, 0), True)
if rx-obj.worldOrientation.to_euler().x > rres:
obj.applyRotation((rres, 0, 0), True)
# print ("delta x ",rx-obj.worldOrientation.to_euler().x)
# y
if ry is not None:
while (abs(ry-obj.worldOrientation.to_euler().y) > rres) :
if obj.worldOrientation.to_euler().y-ry > rres:
obj.applyRotation((0, -rres, 0), True)
if ry-obj.worldOrientation.to_euler().y > rres:
obj.applyRotation((0, rres, 0), True)
# print ("delta y ",ry-obj.worldOrientation.to_euler().y)
# z
if rz is not None:
while (abs(rz-obj.worldOrientation.to_euler().z) > rres) :
if obj.worldOrientation.to_euler().z-rz > rres:
obj.applyRotation((0, 0, -rres), True)
if rz-obj.worldOrientation.to_euler().z > rres:
obj.applyRotation((0, 0, rres), True)
# print ("delta z ",rz-obj.worldOrientation.to_euler().z)
##
# Reset de la manipulation de la vue
##
def manip_reset():
scene.objects['Camera'].worldPosition.x = scene.objects['Camera']['init_lx']
scene.objects['Camera'].worldPosition.y = scene.objects['Camera']['init_ly']
scene.objects['Camera'].worldPosition.z = scene.objects['Camera']['init_lz']
applyRotationTo(scene.objects['System'], 0, 0, 0)
scene.objects['System'].worldPosition.x = scene.objects['System']['init_lx']
scene.objects['System'].worldPosition.y = scene.objects['System']['init_ly']
scene.objects['System'].worldPosition.z = scene.objects['System']['init_lz']
# for objet in scene.objects['System']['objects'] :
# scene.objects[objet].setVisible(True,False)
# scene.objects[objet].restorePhysics()
# if objet+"_Lines.GP" in scene.objects:
# scene.objects[objet+"_Lines.GP"].setVisible(True,False)
##
# Position de départ pour la manipulation de la vue
##
def manip_start(cont):
obj = cont.owner
obj['click_x']=cont.sensors['ClickM'].position[0]
obj['click_y']=cont.sensors['ClickM'].position[1]
##
# Manipulation du modèle ou de la caméra
##
def manip(cont):
obj = cont.owner
sensibilite_orbit=0.0005
sensibilite_pan=0.005
sensibilite_zoom=0.01
delta_x=cont.sensors['DownM'].position[0]-obj['click_x']
delta_y=cont.sensors['DownM'].position[1]-obj['click_y']
# Orbit
if obj['manip_mode']==0:
x0 = scene.objects['Orbit-Hud'].worldPosition.x
y0 =scene.objects['Orbit-Hud'].worldPosition.y
z0 =scene.objects['Orbit-Hud'].worldPosition.z
width = bge.render.getWindowWidth()
height = bge.render.getWindowHeight()
dist_orbit_y_base=200 # Pour 1280 x 720
# radius_orbit_y_base=5
radius_orbit_y_base=0.875
diag_base= math.sqrt(1280**2+720**2)
diag= math.sqrt(width**2+height**2)
dist_orbit_y = dist_orbit_y_base*(diag/diag_base)
radius_orbit_y=radius_orbit_y_base*(diag/diag_base)
dist_orbit = math.sqrt(((width/2)-obj['click_x'])**2+((height/2)-obj['click_y'])**2)
if obj['click_y']> height/2 :
dist_orbit = dist_orbit+((math.sqrt(((height/2)-obj['click_y'])**2)/175)*25) # Correction des Y sous le centre ?
if dist_orbit<dist_orbit_y : # Orbit sur xz
circle ([x0,y0,z0], radius_orbit_y_base, color_cmd)
n=10
# pas_x=(delta_x*40*sensibilite_orbit)/n
pas_x=(delta_x*4*sensibilite_orbit)/n
# pas_y=(((width/2)-cont.sensors['DownM'].position[0])+((height/2)-cont.sensors['DownM'].position[1]))*0.005
pas_y=((((width/2)-cont.sensors['DownM'].position[0])+((height/2)-cont.sensors['DownM'].position[1]))*0.005)/10
# pas_z=(delta_y*40*sensibilite_orbit)/n
pas_z=(delta_y*4*sensibilite_orbit)/n
for i in range (n):
bge.render.drawLine([x0+pas_x*i, y0+abs(pas_y*math.sin((3.14*i)/n)), z0-pas_z*i],
[x0+pas_x*(i+1), y0+abs(pas_y*math.sin((3.14*(i+1))/n)), z0-pas_z*(i+1)],
[0.8, 0.619, 0.021])
scene.objects['System'].applyRotation((delta_y*sensibilite_orbit, 0, delta_x*sensibilite_orbit), False)
else: # Orbit sur y
circle ([x0,y0,z0], radius_orbit_y_base, color_cmd_hl)
if abs(delta_x) >= abs(delta_y):
scene.objects['System'].applyRotation((0, delta_x*sensibilite_orbit, 0), False)
else:
scene.objects['System'].applyRotation((0, delta_y*sensibilite_orbit, 0), False)
# Pan
if obj['manip_mode']==1: # Shift
scene.objects['System'].applyMovement((delta_x*sensibilite_pan, -delta_y*sensibilite_pan, -delta_y*sensibilite_pan), False)
# scene.objects['Camera'].applyMovement((delta_x*-sensibilite_pan, delta_y*sensibilite_pan, 0), True)
# Zoom
if obj['manip_mode']==2: # Ctrl
scene.objects['Camera'].applyMovement((0, 0, (delta_x+delta_y)*sensibilite_zoom), True)
scene.objects['Camera'].applyMovement((0, 0, (delta_x+delta_y)*sensibilite_zoom), True)
##
# Zoom
##
def manip_wheel(cont):
obj = cont.owner
sensibilite_wheel = 20
if cont.sensors['WheelUp'].positive:
scene.objects['Camera'].applyMovement((0, 0, -sensibilite_wheel), True)
if cont.sensors['WheelDown'].positive:
scene.objects['Camera'].applyMovement((0, 0, sensibilite_wheel), True)
###############################################################################
# Fichier
###############################################################################
def file_open():
# Terminer le processus file précédent
if ('file_proc' in scene.objects['System']):
if scene.objects['System']['file_proc'].poll()==None:
scene.objects['System']['file_proc'].terminate()
# Démarrer le processus file
if sys.platform=="linux": # wxPython ne s'installe pas bien sur GNU/linux -> Qt6
scene.objects['System']['file_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "twin_file_qt.py")], stdout=subprocess.PIPE, encoding = 'utf8')
else: # Qt6 ne s'installe pas bien sur Windows -> wxPython
scene.objects['System']['file_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "twin_file_wx.py")], stdout=subprocess.PIPE, encoding = 'utf8')
stout = scene.objects['System']['file_proc'].communicate()
if stout[0][:-1] != 'None':
scene.objects['System']['script'] = stout[0][:-1]
scene.objects['Script-text']['Text']=scene.objects['System']['script']
###############################################################################
# Cycle
###############################################################################
##
# Validation du code Python
##
def python_validation(file):
(pylint_stdout, pylint_stderr) = lint.py_run(file+' --disable=C --disable=W --disable=R', return_std=True)
stdout = pylint_stdout.read()
stderr = pylint_stderr.read()
if " error (" in stdout: # Présence d'erreur
# UI : information
scene.objects['Cmd-text']['modal']= True
scene.objects['Cmd-text']['Text']= "Erreur dans le script ... "
scene.objects['Cmd-text'].setVisible(True,False)
print(stdout) # Affichage console
return False
else:
scene.objects['Cmd-text']['modal']= False
scene.objects['Cmd-text']['Text']= ""
scene.objects['Cmd-text'].setVisible(False,False)
return True
##
# Mise en route et pause du cycle
##
def cycle_run ():
# Pause
if scene.objects['System']['run'] == True:
scene.objects['System']['run']=False
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause'].suspendPhysics()
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Run'].restorePhysics()
scene.objects['Run-Hl'].setVisible(True,False)
# Run
else :
scene.objects['System']['run']=True
scene.objects['Run'].setVisible(False,False)
scene.objects['Run'].suspendPhysics()
scene.objects['Run-Hl'].setVisible(False,False)
# scene.objects['Pause']. restorePhysics() # FIXME pause pas implémentée
# scene.objects['Pause'].setVisible(True,False) # FIXME pause pas implémentée
# Démarrage du cycle
if scene.objects['System']['thread_cmd']==False:
time.sleep(0.125)
scene.objects['System']['thread_cmd']=True
system.system_reset()
time.sleep(0.125)
scene.objects['System']['time']=0
scene.objects['System']['daq']=False
scene.objects['System']['plot']=False
module_name=os.path.split((scene.objects['System']['script']))[1][:-3]
if python_validation(scene.objects['System']['script']):
runpy.run_path(scene.objects['System']['script'], run_name='start') # Execution du script utilisateur
# Arrêt de la pause
else:
# FIXME : Relancer la maquette
pass
##
# Arrêt et réinitialisation du cycle (forçage)
##
def cycle_stop ():
scene.objects['System']['thread_cmd']=False
system.system_reset()
##
# Fin du cycle
##
def cycle_end (cont):
if cont.sensors['End cycle'].positive:
scene.objects['System']['run']=False
module_name=os.path.split((scene.objects['System']['script']))[1][:-3]
if python_validation(scene.objects['System']['script']):
runpy.run_path(scene.objects['System']['script'], run_name='stop') # Fin du script utilisateur
# Commandes
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause'].suspendPhysics()
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Run'].setVisible(True,False)
scene.objects['Run'].restorePhysics()
##
# Highlight sur les éléments cliquable du systèmes
##
def cycle_hl(cont):
if "-colbox" in cont.owner.name:
obj= scene.objects[cont.owner.name[:-7]]
else:
obj = cont.owner
# Activation
if cont.sensors['MO'].status == JUST_ACTIVATED:
obj['mo'] = True
# Composant avec un goupe de couleur (type actionneur)
if "color_group" in obj.getPropertyNames():
for obj_name in obj['color_group']:
scene.objects[obj_name].color = color_hl
else:
obj.color = color_hl
# Description
if obj['description'] is not None:
scene.objects['Cmd-text']['Text']=obj['description']
scene.objects['Cmd-text'].setVisible(True,True)
# Désactivation
if cont.sensors['MO'].status == JUST_RELEASED :
obj['mo'] = False
scene.objects['Cmd-text']['Text']=""
# Composant passif
if "active" in obj.getPropertyNames():
if obj['active'] == False: # Composant passif
obj.color = color_passive
return
# Composant avec un goupe de couleur (type actionneur)
if "color_group" in obj.getPropertyNames():
for obj_name in obj['color_group']:
cycle_actuator_color(obj_name)
return
# Composant simple
obj.color = color_active
##
# Click sur les éléments cliquables du système (activation numérique)
##
def cycle_click(cont):
obj = cont.owner
if scene.objects['System']['run'] ==False:
return
# Passif
if "active" in obj.getPropertyNames():
if obj['active'] == False:
obj.color = color_passive
return
# Activation
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['System']['manip_mode']==0 and obj['prior']:
obj.color = color_activated
obj['activated'] = True
obj['click'] = True
# Désactivation
if cont.sensors['Click'].status == JUST_RELEASED and obj['prior']:
obj['activated'] = False
obj['click'] = False
if cont.sensors['MO'].positive:
obj.color = color_hl
else:
obj.color = color_active
##
# Couleurs sur les éléments sensibles du système
##
def cycle_sensitive_color(obj):
# Mouse over
if obj['mo'] == True and obj['click'] == False and obj.color !=color_hl:
obj.color =color_hl
# Jumeau
elif scene.objects['System']['twins']:
if obj['activated_real'] ==False and obj['activated']==False and obj.color !=color_active:
obj.color =color_active
elif obj['activated_real'] and obj['activated'] and obj.color !=color_activated_dbl:
obj.color =color_activated_dbl
elif obj['activated_real'] and obj['activated']==False and obj.color !=color_activated_real:
obj.color =color_activated_real
elif obj['activated_real'] ==False and obj['activated'] and obj.color !=color_activated:
obj.color =color_activated
elif obj['activated_real'] ==False and obj['activated']==False and obj.color !=color_activated:
obj.color =color_active
# Uniquement maquette 3D
else:
if obj['activated'] == True and obj.color !=color_activated:
obj.color =color_activated
elif obj['activated'] == False and obj.color !=color_active:
obj.color =color_active
##
# Couleurs des actionneurs
##
def cycle_actuator_color(name):
obj = scene.objects[name]
if obj['color']== "blue":
obj.color = color_blue
elif obj['color']== "blue-dark":
obj.color = color_blue_dark
elif obj['color']== "grey":
obj.color = color_grey
elif obj['color']== "led_yellow":
obj.color = color_led_yellow
##
# Comportement standard des boutons
##
def cycle_bp(cont):
obj = cont.owner
# Arduino -> Modele 3D
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None :
if obj['pin'].read()==True and obj['activated_real'] == False :
obj['activated_real'] = True
if obj['pin'].read()==False and obj['activated_real'] == True :
obj['activated_real'] = False
# Couleurs
cycle_sensitive_color(obj)
##
# Comportement standard des voyants
##
def cycle_voy(cont):
obj = cont.owner
obj_on=scene.objects[obj.name+"-on"]
# Mouse over
if obj['mo'] == True and obj.color !=color_hl:
obj.color =color_hl
elif scene.objects['System']['run']:
# Activation
if obj['activated'] and obj_on.visible == False:
# Modele 3D
if obj['prior']:
obj_on.setVisible(True,False)
obj.setVisible(False,False)
# Modele 3D -> Arduino
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
obj['pin'].write(1)
# Désactivation
if obj['activated']==False and obj_on.visible == True:
# Modele 3D
if obj['prior']:
obj.setVisible(True,False)
obj_on.setVisible(False,False)
# Modele 3D -> Arduino
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
obj['pin'].write(0)
##
# Mise en couleur des actionneurs
##
def cycle_def_focusgroup(focusgroup, description):
group=[]
for obj in focusgroup:
group.append(obj[0])
for obj in focusgroup:
scene.objects[obj[0]]['color_group'] = group
scene.objects[obj[0]]['color'] = obj[1]
scene.objects[obj[0]]['description']=description
cycle_actuator_color(obj[0])