Boutique Cinema 4D
Affichage des résultats 1 à 6 sur 6

Discussion: PointeuseY

  1. #1
    Pilier Avatar de xs_yann
    Date d'inscription
    février 2005
    C4D version
    R19 Studio
    OS
    Mac OS X 10.13
    Messages
    1 990

    PointeuseY

    Salut à tous,

    Je vous partage un petit exercice Python que j’ai fait, qui consiste à recoder La PointeuseX™ de Jean-Laurent en Python.

    http://frenchcinema4d.fr/showthread....-temps-pass%E9

    Le principe de Jean-Laurent était de comparer à chaque exécution la minute courante avec celle de l’exécution précédente et en cas de différence (une ou plusieurs minutes écoulées), ajouter cette différence au compteur.

    Le principe que j’ai utilisé est de calculer le temps écoulé entre chaque exécution (aussi court soit-il) et de l’ajouter au compteur.



    Valeur : La valeur courante du compteur (il est possible de la modifier manuellement).
    Inactivité : Temps d’inactivité à partir duquel le compteur n’enregistre plus.
    Limite de temps : Permet d’arrêter le compteur lorsque ce temps est atteint.
    Compte à rebours : Si une limite de temps est définie, le compteur se décrémente au lieu de s’incrémenter.
    Heures:Minutes : 2:30
    Heures:Minutes:Secondes : 2:30:02
    Total Minutes : 150
    Total Heures : 2.5

    Le code généré par le script se trouve dans un noeud Python d’un tag Xpresso, ce qui permet de récupérer facilement la sortie pour la connecter avec ce que l’on veut. Par défaut la sortie est connectée avec le nom de l’objet neutre pour voir le temps dans le gestionnaire d’objet ou pour l’ajouter à l’HUD.



    Exemple avec une spline Texte :





    La petite particularité est que tout est généré à partir d’un script, ce qui permet de ne pas dépendre d’un fichier c4d (comme la plupart des presets Xpresso). Le script créé l’objet neutre avec ses données utilisateur puis le tag Xpresso et le noeud Python avec son code dedans.

    Voici le code :
    Code PHP:
    import c4d

    ID_OPERATOR_PYTHON 
    1022471

    _display_modes 
    = ["DISPLAY_H""DISPLAY_M""DISPLAY_HM""DISPLAY_HMS"]

    NODE_CODE """import c4d
    from datetime import datetime, timedelta
    import re

    CONTAINER_ID = 1033688
    ELAPSED_SEC = 100
    ELAPSED_MICRO = 101

    __ENUM_IDS__

    _languages = ['fr', 'us']

    _strings = {
        # User Data
        UD_HIDE: {'us':"
    Hide", 'fr':"Masquer"},
        UD_VALUE:  {'us':"
    Value", 'fr':"Valeur"},
        UD_RESET: {'us':"
    Reset", 'fr':"Remise à zéro"},
        UD_IDLE: {'us':"
    Idle", 'fr':"Inactivité"},
        UD_TIME_LIMIT: {'us':"
    Time limit", 'fr':"Limite de temps"},
        UD_COUNTDOWN: {'us':"
    Countdown", 'fr':"Compte à rebours"},
        UD_DISPLAY: {'us':"
    Display", 'fr':"Affichage"},
        
        # Cycles
        (UD_DISPLAY, DISPLAY_H): {'us':"
    Total Hours", 'fr': "Total Heures"},
        (UD_DISPLAY, DISPLAY_M): {'us':"
    Total Minutes", 'fr': "Total Minutes"},
        (UD_DISPLAY, DISPLAY_HM): {'us':"
    Hours:Minutes", 'fr': "Heures:Minutes"}, 
        (UD_DISPLAY, DISPLAY_HMS): {'us':"
    Hours:Minutes:Seconds", 'fr': "Heures:Minutes:Secondes"},
        
        # Strings
        'Show': {'us':"
    Show", 'fr': "Afficher"},
        'Hide': {'us':"
    Hide", 'fr':"Masquer"},
        'Finished': {'us':"
    Finished", 'fr':"Terminé"},
    }

    def get_default_language():
        i = 0
        while True:
            lang = c4d.GeGetLanguage(i)
            if lang is None:
                break
            if lang["
    default_language"]:
                lang = lang["
    extensions"].lower()
                return lang if lang in _languages else 'us'
            i += 1

    def tr(s):
        lang = get_default_language().lower()
        if s in _strings:
            return _strings[s][lang]
        return s

    def translate_ud(obj, lang):
        for desc, bc in obj.GetUserDataContainer():
            if not desc[1].id in _strings:
                continue
            name = _strings[desc[1].id][lang]
            bc[c4d.DESC_NAME] = name
            bc[c4d.DESC_SHORT_NAME] = name
            bc_cycle = bc[c4d.DESC_CYCLE]
            if bc_cycle:
                for k, v in bc_cycle:
                    bc_cycle[k] = _strings[(desc[1].id, k)][lang]
                bc.SetContainer(c4d.DESC_CYCLE, bc_cycle)
            obj.SetUserDataContainer(desc, bc)


    _date = None
    _total = None
    _lang = None

    class Duration(timedelta):
        
        @staticmethod
        def parse(s=""):
            \"""Create timedelta from string.
            \"""
            regex = r'((?P<hours>\d+):)?((?P<minutes>\d+):?)(?P<seconds>\d+)?'
            match_object = re.match(regex, str(s).replace(" ", ""))
            if match_object is None:
                return Duration()
            args = dict((k, int(v)) for k, v in match_object.groupdict(default=0).items())
            return Duration(**args)
        
        def __add__(self, x):
            y = super(Duration, self).__add__(x)
            return Duration(days=y.days, seconds=y.seconds, microseconds=y.microseconds)
        
        def __sub__(self, x):
            y = super(Duration, self).__sub__(x)
            return Duration(days=y.days, seconds=y.seconds, microseconds=y.microseconds)

        def __str__(self):
            return self.fmt("
    {th} : {m} : {s}")
        
        def total_seconds(self, cast=int):
            \"""Total seconds from timedelta.
            \"""
            return (self.microseconds + (self.seconds + self.days * 24 * 3600) * 10 ** 6) / cast(10 ** 6)

        def fmt(self, fmt):
            \"""String format.
            \"""
            seconds = self.total_seconds()
            d = {'d': self.days}
            d['h'], rem = divmod(self.seconds, 3600)
            d['m'], d['s'] = divmod(rem, 60)
            d['m'] = "
    {0:02d}".format(d['m'])
            d['s'] = "
    {0:02d}".format(d['s'])
            d['th'], d['tm'], d['ts'] = seconds / 3600, seconds / 60, seconds
            d['thf'] = "
    {0:.1f}".format(seconds / 3600.0)
            return fmt.format(**d)
        
    def reset(default=Duration()):
        global _date
        global _total
        
        _total = default
        _date = datetime.now()
        return default

    def get_container(obj, container_id):
        bc = obj[container_id]
        if not bc:
            bc = c4d.BaseContainer()
            obj[container_id] = bc
        return bc

    def init(doc, controller, value):
        \"""Init previous date and total elapsed time.
        \"""
        global _total
        global _lang
        
        if _lang is None:
            container = get_container(doc, CONTAINER_ID)
            _lang = get_default_language().lower()
            translate_ud(controller, _lang)

        if _total is None:
            reset(value)
            container = get_container(doc, CONTAINER_ID)
            sec, micro = container[ELAPSED_SEC], container[ELAPSED_MICRO]
            if sec is not None and micro is not None:
                _total = Duration(seconds=sec, microseconds=micro)
        elif str(_total) != str(value):
            reset(value)

    def get_delta():
        \"""Return elapsed time from last execution.
        \"""
        global _date
        
        now = datetime.now()
        delta = now - _date
        _date = now
        return delta

    def update(delta, idle, doc, controller):
        \"""Update total and ouput.
        \"""
        global _total
       
        if delta < idle or idle.total_seconds() == 0:
            _total += delta
            
        set_ud(controller, UD_VALUE, str(_total))
        container = get_container(doc, CONTAINER_ID)
        container[ELAPSED_SEC] = _total.total_seconds()
        container[ELAPSED_MICRO] = _total.microseconds
        doc.GetDataInstance().SetContainer(CONTAINER_ID, container)

    def format_time(time_limit, display, countdown):
        \"""Format output string.
        \"""
        global _total
        
        formatted = ""
        if _total >= time_limit and time_limit.total_seconds() != 0:
            formatted = tr("
    Finished")
        else:
            total = _total
            if countdown and time_limit.total_seconds() != 0:
                total = time_limit - total
            fmts = {DISPLAY_M: "
    {tm}", DISPLAY_H: "{thf}", DISPLAY_HM: "{th}:{m}", DISPLAY_HMS:"{th}:{m}:{s}"}
            formatted = total.fmt(fmts[display])
        return formatted

    def get_ud(op, id_ud):
        return op[c4d.ID_USERDATA, id_ud]

    def set_ud(op, id_ud, value):
        op[c4d.ID_USERDATA, id_ud] = value

    def create_layer(obj, name):
        layer = c4d.documents.LayerObject()
        layer.SetName(name)
        layer_root = doc.GetLayerObjectRoot()
        layer.InsertUnder(layer_root)
        obj.SetLayerObject(layer)
        return layer

    def hide(doc, obj):
        layer = obj.GetLayerObject(doc)
        if layer is None:
            layer = create_layer(obj, "
    PointeuseY")
        data = layer.GetLayerData(doc)
        # Show / Hide Layer
        data['manager'] = not data['manager']
        layer.SetLayerData(doc, data)
        
        # Switch button name
        ud_bc = obj.GetUserDataContainer()
        hide_bc, hide_desc = dict((desc[1].id, (bc, desc)) for desc, bc in ud_bc)[UD_HIDE]
        names = [tr("
    Show"), tr("Hide")] 
        hide_bc[c4d.DESC_NAME] = names[data['manager']]
        hide_bc[c4d.DESC_SHORT_NAME] = names[data['manager']]
        obj.SetUserDataContainer(hide_desc, hide_bc)

    def main():
        
        global __OUTPUT__ # Output Node
        
        controller = op.GetNodeMaster().GetOwner().GetObject()
        
        value = Duration.parse(get_ud(controller, UD_VALUE))
        idle = Duration.parse(get_ud(controller, UD_IDLE))
        time_limit = Duration.parse(get_ud(controller, UD_TIME_LIMIT))
        set_ud(controller, UD_IDLE, str(idle))
        set_ud(controller, UD_TIME_LIMIT, str(time_limit))
        
        countdown = get_ud(controller, UD_COUNTDOWN)
        display = get_ud(controller, UD_DISPLAY)
        
        if get_ud(controller, UD_RESET):
            value = reset()
            set_ud(controller, UD_RESET, False)
            
        if get_ud(controller, UD_HIDE):
            hide(doc, controller)
            set_ud(controller, UD_HIDE, False)
        
        init(doc, controller, value)
        delta = get_delta()
        update(delta, idle, doc, controller)
        __OUTPUT__ = format_time(time_limit, display, countdown)
    """

    def create_UD_container(objdtypenameparent):
        
    bc c4d.GetCustomDataTypeDefault(dtype)
        
    bc[c4d.DESC_NAME] = name
        bc
    [c4d.DESC_SHORT_NAME] = name
        bc
    [c4d.DESC_PARENTGROUP] = parent
        
    return bc

    def create_UD_default
    (objbc, default):
        
    bc[c4d.DESC_DEFAULT] = default
        
    ud obj.AddUserData(bc)
        
    obj[ud] = default
        return 
    ud

    def create_UD_group
    (objnameparent=None):
        
    bc create_UD_container(objc4d.DTYPE_GROUPnameparent)
        return 
    obj.AddUserData(bc)

    def create_UD_string(objnameparent=None, default=""):
        
    bc create_UD_container(objc4d.DTYPE_STRINGnameparent)
        return 
    create_UD_default(objbc, default)

    def create_UD_bool(objnameparent=None, default=Falsegui=c4d.CUSTOMGUI_BOOL):
        
    bc create_UD_container(objc4d.DTYPE_BOOLnameparent)
        
    bc[c4d.DESC_CUSTOMGUI] = gui
        
    return create_UD_default(objbc, default)

    def create_UD_cycle(objnameparent=None, default=0populate={}):
        
    bc create_UD_container(objc4d.DTYPE_LONGnameparent)
        
    bc[c4d.DESC_CUSTOMGUI] = c4d.CUSTOMGUI_CYCLE
        items 
    c4d.BaseContainer()
        for 
    iitem in populate.iteritems():
            
    items.SetString(iitem)
        
    bc[c4d.DESC_CYCLE] = items
        
    return create_UD_default(objbc, default)

    def create_userdata(null):
        
    group create_UD_group(null"PointeuseY"c4d.DescID(0))
        
    ud_ids = {}
        
    ud_ids["UD_VALUE"] = create_UD_string(null""group"0:00:00")[1].id
        ud_ids
    ["UD_RESET"] = create_UD_bool(null""groupgui=c4d.CUSTOMGUI_BUTTON)[1].id
        ud_ids
    ["UD_IDLE"] = create_UD_string(null""group"0:05:00")[1].id
        ud_ids
    ["UD_TIME_LIMIT"] = create_UD_string(null""group"3:00:00")[1].id
        ud_ids
    ["UD_COUNTDOWN"] = create_UD_bool(null""group)[1].id
        items 
    dict((i"dummy") for imode in enumerate(_display_modes))
        
    ud_ids["UD_DISPLAY"] = create_UD_cycle(null""grouppopulate=items, default=3)[1].id
        ud_ids
    ["UD_HIDE"] = create_UD_bool(null""groupgui=c4d.CUSTOMGUI_BUTTON)[1].id
        
    return ud_ids

    def create_xpresso
    (nullud_ids):
        
    xpresso c4d.BaseTag(c4d.Texpresso)
        
    null.InsertTag(xpresso)
        
    master xpresso.GetNodeMaster()
        
    python_node master.CreateNode(master.GetRoot(), ID_OPERATOR_PYTHONx=10y=100)
        
    formatted_port python_node.AddPort(c4d.GV_PORT_OUTPUTc4d.OUT_STRINGmessage=True)
        
    python_node[c4d.GV_PYTHON_CODE] = generate_code(ud_idsformatted_port.GetName(python_node))
        
        
    null_node master.CreateNode(master.GetRoot(), c4d.ID_OPERATOR_OBJECTx=300y=100)
        
    null_node[c4d.GV_OBJECT_OBJECT_ID] = null
        name_port 
    null_node.AddPort(c4d.GV_PORT_INPUTc4d.ID_BASELIST_NAME)
        
    name_port.Connect(formatted_port)
        
    python_node.RemoveUnusedPorts()

    def generate_code(ud_idsoutput_name):
        
    enum_ids ""
        
    for imode in enumerate(_display_modes):
            
    enum_ids += "{0} = {1}\n".format(modei)
        for 
    kv in ud_ids.iteritems():
            
    enum_ids += "{0} = {1}\n".format(kv)
        return 
    NODE_CODE.replace("__ENUM_IDS__"enum_ids).replace("__OUTPUT__"output_name)

    def create_object(docobject_type):
        
    obj c4d.BaseObject(object_type)
        
    doc.InsertObject(obj)
        
    doc.AddUndo(c4d.UNDO_NEWobj)
        
    doc.SetActiveObject(obj)
        return 
    obj
        
    def main
    ():
        
    null create_object(docc4d.Onull)
        
    ud_ids create_userdata(null)
        
    create_xpresso(nullud_ids)
        
        
    c4d.EventAdd(c4d.EVENT_0)

    if 
    __name__=='__main__':
        
    main() 
    http://xsyann.com/fc4d/PointeuseY.py


    edit : J'avais oublié que Val l'avait déjà fais aussi, si vous voulez un chrono en mode plugin avec l'utilisation d'un vrai timer c'est ici : http://frenchcinema4d.fr/showthread.php?74574-Py-Timer
    Dernière modification par xs_yann ; 03/10/2014 à 17h43.

  2. #2
    Pilier Avatar de oli_d
    Date d'inscription
    avril 2004
    C4D version
    Autre
    OS
    MacOS X
    Messages
    707
    Merci pour le partage, ton code est une vraie leçon de programmation.

    Par contre sur la version française de c4d il plante, car la traduction de string est Chaîne, donc le code du noeud python plante sur la définition de ton port de sortie à cause de l'accent circonflexe ! (je sais pas s'il y a quelqu'un qui m'a compris là !)

    Message d'erreur :
    File "'Python'", line 126
    global Chaîne # Output Node
    ^
    SyntaxError: invalid syntax
    Je continue à décortiquer, car j'apprends plein de trucs !

  3. #3
    Pilier Avatar de xs_yann
    Date d'inscription
    février 2005
    C4D version
    R19 Studio
    OS
    Mac OS X 10.13
    Messages
    1 990
    Ah mince, merci du retour oli_d.
    Pourtant j'ai pensé à ce cas et j'ai injecté dynamiquement dans le code le nom du noeud que je récupère dans le script...
    Malheureusement, le bug que j'ai posté dans le thread de César empêche de corriger ça.
    Peut-être que je peux récupérer le nom du port automatiquement dans le noeud python, à voir.

    edit :
    Après avoir essayé de modifier manuellement le dictionnaire des globales, d'évaluer le nom du port, d'inspecter les membres de la classe port, d'utiliser un type Filename plutôt que String (ça fonctionne mais en français "Nom de Fichier" ça passe pas non plus en nom de variable), j'ai trouvé une solution qui consiste à appeler la fonction GvNode.AddPort avec message=True, je ne sais pas pourquoi mais le port s'appelle Output2 au lieu de String (ou Chaîne).

    Code PHP:
    output_port python_node.AddPort(c4d.GV_PORT_OUTPUTc4d.OUT_STRINGmessage=True
    J'ai essayé aussi de changer le type du port Output1 de base (qui est en Real par défaut) avec GvNode.SetPortType, ça fonctionne mais que si la fonction AddPort est appelée avant avec le même id que SetPortType(), ce qui revient à créer un noeud pour rien qu'il faut supprimer après...
    Code PHP:
    python_node.AddPort(c4d.GV_PORT_OUTPUTc4d.OUT_STRING)
    output_port python_node.GetOutPort(0)
    python_node.SetPortType(output_portc4d.OUT_STRING
    Dernière modification par xs_yann ; 01/10/2014 à 22h44.

  4. #4
    Gourou Avatar de valkaari
    Date d'inscription
    mai 2009
    C4D version
    Autre
    OS
    OSX / windows
    Messages
    2 949
    c'était presque trop facile quoi

  5. #5
    Pilier Avatar de miroof
    Date d'inscription
    janvier 2012
    C4D version
    R16 Studio
    Messages
    919
    Oh c'est nickel ça, merci pour les liens
    Expert en l'art de ne jamais finir mes WIPs persos

  6. #6
    Pilier Avatar de xs_yann
    Date d'inscription
    février 2005
    C4D version
    R19 Studio
    OS
    Mac OS X 10.13
    Messages
    1 990
    J'ai ajouté un undo, un bouton afficher / masquer et une traduction français / anglais.



    Le bouton 'Masquer' créé un calque et le masque dans le gestionnaire d'objet. L'idéal est de créer une entrée dans l'HUD en faisant un cliquer-glisser du nom de l'objet neutre sur la vue. Cela permet, en plus d'afficher le temps, de pouvoir retrouver facilement l'objet masqué en cliquant dessus.

    Le bout de code qui change dynamiquement le nom d'un bouton en DU :
    Code PHP:
    state 0
    ud_bc 
    obj.GetUserDataContainer()
    hide_bchide_desc dict((desc[1].id, (bcdesc)) for descbc in ud_bc)[BUTTON_ID]
    names = [tr("Show"), tr("Hide")] 
    hide_bc[c4d.DESC_NAME] = names[state]
    hide_bc[c4d.DESC_SHORT_NAME] = names[state]
    obj.SetUserDataContainer(hide_deschide_bc
    La traduction est gérée par une fonction qui récupère le langage courant et qui traduit les chaîne de caractères en fonction de ce langage. De cette façon les noms des DU générées et le nom dynamique du bouton sont traduits.

    edit : J'ai modifié le code pour que le preset traduise automatiquement son interface (les données utilisateur) à chaque ouverture.
    Dernière modification par xs_yann ; 03/10/2014 à 17h46.

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •  
Mediaworks - Logiciels 3D | Design Internet - Creation site internet