jumeaux-numeriques/twin.py

943 lines
34 KiB
Python
Raw Permalink 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)
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-2024 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():
# Configuration de l'écran
bge.render.setWindowSize(int(twin_config[0][0].text),int(twin_config[0][1].text))
scene.objects['About']['quality'] = int(twin_config[0][2].text)
twin_about.quality_apply(scene.objects['About']['quality'], True)
# 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", "Credits")
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):
# Texte
if scene.objects['Cmd-text']['modal']:
scene.objects['Cmd-text']['Text']= "Erreur dans le script ... "
scene.objects['Cmd-text'].setVisible(True,False)
else:
scene.objects['Cmd-text']['Text']= ""
scene.objects['Cmd-text'].setVisible(False,False)
# Icone
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()
system.system_reset()
# 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['Credits'].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 -> Qt5
scene.objects['System']['file_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "twin_file_qt.py")], stdout=subprocess.PIPE, encoding = 'utf8')
else: # Qt5 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')
# Récupérer le nom du fchier
stout = scene.objects['System']['file_proc'].communicate()
if stout[0][:-1] != 'None' and len(stout[0][:-1])>0 :
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):
# Terminer le processus fils précédent
if ('pylint_proc' in scene.objects['Commands']):
if scene.objects['Commands']['pylint_proc'].poll()==None:
scene.objects['Commands']['pylint_proc'].terminate()
# Lancer le processus fils
scene.objects['Commands']['pylint_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "twin_pylint.py"), file], stdout=subprocess.PIPE, encoding = 'utf8')
stout = scene.objects['Commands']['pylint_proc'].communicate()
# Présence d'erreur
if stout[0][:-1] != 'None' and len(stout[0][:-1])>0 :
# UI : information
scene.objects['Cmd-text']['modal']= True
scene.objects['Cmd-text']['Text']= "Erreur dans le script ... "
scene.objects['Cmd-text'].setVisible(True,False)
# Affichage console
stout_lines = stout[0].split("\n")
for stout_line in stout_lines:
print ("Pylint :", stout_line) # Affichage console
return False
# Absence d'erreur
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
scene.objects['Twins-text']['Text'] = "Connection fermée."
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 groupe de couleur
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 groupe de couleur
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 normalement ouverts (NO) 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 cont.sensors['MO'].positive and obj['prior']:
obj['activated'] = False
obj['click'] = False
if cont.sensors['MO'].positive:
obj.color = color_hl
else:
obj.color = color_active
##
# Click sur les éléments cliquables normalement fermés (NC)
# Lors de l'activation la valeur est False
##
def cycle_click_nc(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_active
obj['activated'] = False
obj['click'] = True
# Désactivation
if cont.sensors['Click'].status == JUST_RELEASED and cont.sensors['MO'].positive and obj['prior']:
obj['activated'] = True
obj['click'] = False
if cont.sensors['MO'].positive:
obj.color = color_hl
else:
obj.color = color_activated
##
# Click sur les éléments rémanents (activation numérique)
# Lors de la désactivation, activated reprend la valeur d'avant le click
##
def cycle_click_persistent(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_prev'] = obj['activated']
obj['activated'] = True
obj['click'] = True
# Désactivation
if cont.sensors['Click'].status == JUST_RELEASED and cont.sensors['MO'].positive and obj['prior']:
obj['activated'] = obj['activated_prev']
obj['click'] = False
if cont.sensors['MO'].positive:
obj.color = color_hl
else:
if obj['activated_prev'] :
obj.color = color_activated
else:
obj.color = color_active
obj['activated_prev'] = False
##
# Click sur les éléments commutables du système (activation numérique)
##
def cycle_switch(cont):
obj = cont.owner
obj_on=scene.objects[obj.name+"-on"]
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']:
if obj['activated']: # On -> Off
obj.color = color_hl
obj['activated'] = False
obj['click'] = True
obj.setVisible(True,False)
obj_on.setVisible(False,False)
else: # Off -> On
obj_on.color = color_activated
obj['activated'] = True
obj['click'] = True
obj_on.setVisible(True,False)
obj.setVisible(False,False)
# Désactivation
if cont.sensors['Click'].status == JUST_RELEASED and obj['prior']:
obj['click'] = False
if cont.sensors['MO'].positive:
obj.color = color_hl
else:
if obj['activated']:
obj_on.color = color_activated
else:
obj.color = color_active
##
# Couleurs sur les éléments sensibles du système
# obj : objet numériquegb
# obj_on : objet numérique à l'état activé (si différent)
##
def cycle_sensitive_color(obj, obj_on=None):
# 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
if obj_on is not None:
obj_on.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
if obj_on is not None:
obj_on.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 poussoirs
##
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 boutons à glissière
##
def cycle_bg(cont):
obj = cont.owner
obj_on=scene.objects[obj.name+"-on"]
# 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, obj_on)
##
# Comportement standard des capteurs (analogique)
##
def cycle_sensor(cont):
obj = cont.owner
# Physique du modèle 3D
if scene.objects['System']['run']:
if obj['activated'] and obj['value']!=obj['value_click']:
obj['value']=obj['value_click']
if obj['activated']==False and obj['value']!=obj['value_unclick']:
obj['value']=obj['value_unclick']
# Arduino -> Modele 3D
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None :
obj['value_real'] = obj['pin'].read()
##
# 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']:
# Physique du modèle 3D
if obj_on.visible == False and 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:
# Physique du modèle 3D
if obj_on.visible == True and 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])