PDA

Voir la version complète : Question Toggle Tools - Comment adapter à la R16 le script réalisé par Sandi Dolšak



Sunlight84
09/01/2015, 14h39
Bonjour à tous, ceci est mon premier post sur ce forum, je remercie d'avance les personnes qui prendront le temps de me lire et de me guider dans les démarches à entreprendre pour épouser au mieux la philosophie du forum.


Voici une vidéo de présentation du script en question :

http://vimeo.com/14593733


http://vimeo.com/14593733

Le but de ce script est de permettre un basculement entre différents outils ou options d'outils à l'aide d'une seule touche au clavier.

( Par exemple , par défaut dans Cinema 4D, la touche "Entrée" fait déjà ce boulot pour basculer entre les sous-objets "Points", "Edges" et "Polygons. )

Hélas le script est indisponible, je ne connais absolument rien à python et mes tentatives de ré-écrire les scripts à partir de la vidéo tombent presque toutes à l'eau.

J'aimerais en effet réussir à créer par exemple, un Basculement entre les outils "bridge,Slide,Stitch and Sew" à l'aide d'une seule touche.

Voici une première piste trouvée ici : http://forums.cgsociety.org/archive/index.php/t-1014461.html


var op = doc->GetActiveObject(); if(!op)return;

if(!IsCommandChecked(450000008) && !IsCommandChecked(450000012))
CallCommand(450000008); // Bridge
else if(IsCommandChecked(450000008)) {
CallCommand(450000012); // Slide
} else if(IsCommandChecked(450000012)) {
CallCommand(450000011); // Stitch and Sew
} else CallCommand(450000008); // Bridge

Hélas, ça ne fonctionne pas et malgré toute mes recherches sur le net et mes tentative pour comprendre le langage, je ne fais que perdre du temps.

J'aimerais aussi adapter ce script qui sert à basculer entre les différentes option du Knife pour y ajouter le MODE 3 et le MODE 4 :


if(!IsCommandChecked(1016030) || tool()#MDATA_KNIFE_MODE != 0) {
CallCommand(1016030); // Knife
tool()#MDATA_KNIFE_MODE = 0;
} else {
tool()#MDATA_KNIFE_MODE = 2;
tool()#MDATA_KNIFE_RESTRICT = FALSE;
}

Ce script ne fonctionne hélas que pour switcher entre l'option "line" et "loop", j'aimerais donc ajouter le mode "plane" et "path".

Ensuite dans le vidéo on peut voir qu'il utilise la même méthode pour switcher entre les différents mode de sélections "loop", "ring" et "fill selection". Encore une fois, je serais ravis de recevoir de l'aide pour reproduire ce genre de choses.

Merci à tout ceux qui m'ont lu jusqu'ici !




Pour ma part je suis un nouvel utilisateur de Cinema4D, j'ai migré il y a peu depuis 3DSmax !
Je me suis spécialisé dans la modélisation architecturale photo-réaliste.
Je travaille sous Windows 7 64bits avec la version R16 Studio de Cinema4D.

J'utilise un périphérique "Razer Orbweaver" lorsque je modélise, c'est pourquoi il me serait utile de pouvoir créer des option de basculement entre différents outils.

sansalvador
09/01/2015, 15h00
je vais peut être dire une bêtise , mais pourquoi ne pas tout simplement utiliser les raccourcis clavier ?

Sunlight84
09/01/2015, 15h10
Merci d'avoir pris le temps de me lire sansalvador.

En effet quand on voit l'ampleur du truc, on se demande tout à fait légitimement pourquoi ne pas se contenter d'utiliser les raccourcis clavier d'origine de Cinema4D.

Au fond, c'est tout à fait personnel comme démarche, je trouve plus pratique de basculer entre les outils à l'aide d'une seule touche configurée sur l'Orbweaver.

oli_d
09/01/2015, 15h35
Salut et bienvenue,
chez moi le premier script fonctionne en r16. Attention ce n'est pas du python mais du COFFEE, et il faut avoir un objet sélectionné et en plus être en mode arrêtes ou points pour que cela fonctionne (en mode polygone on reste sur l'outil ponter).

Le second fonctionne sans autre ...

Tu as bien ouvert le gestionnaire de scripts, ensuite choisir l'onglet COFFEE, puis Fichier/Nouveau (dans le menu du gestionnaire de script) puis coller le code et bouton exécuter

Sunlight84
09/01/2015, 15h59
Salut oli_d, merci à toi aussi d'avoir pris le temps de lire mon message et pour ton souhait de bienvenue !!

En effet j'étais resté en mode polygons !! Le script fonctionne parfaitement en mode Edges et Points.

C'est excellent ! Merci beaucoup pour ton aide.

Ensuite, tu disais "Le second fonctionne sans autre ..." je ne comprends pas bien ce que tu as voulu dire, pourrais-tu développer ?
Tu penses que ce n'est pas possible d'ajouter le mode "plane" et "path" au script ?

Je vais essayer d'adapter le premier script aux outils "extrude" " extrude inner" et "bevel"
Je posterais le résultat si j'obtiens quelquechose qui fonctionne.

Si tu pense que c'est possible d'expliquer les bases de l'écriture de ce genre de script, je suis preneurs :P

Encore merci et n'hésite pas à commenter sur la possibilité de créer un basculement entre les outils de selections ring,loop et fil selection.

EDIT:

Voilà je poste le script pour switcher entre "extrude/extrude Inner et Bevel"

var op = doc->GetActiveObject(); if(!op)return;


if(!IsCommandChecked(1011183) && !IsCommandChecked(450000004))
CallCommand(1011183); // Extrude
else if(IsCommandChecked(1011183)) {
CallCommand(450000004); // Extrude Inner
} else if(IsCommandChecked(450000004)) {
CallCommand(431000015); // Bevel
} else CallCommand(1011183); // Extrude

Sunlight84
09/01/2015, 16h33
Alors alors, en ce qui concerne un script pour les sélections, j'ai simplement remplacer les valeurs correspondantes avec "loop selection", "ring selection" et "outline selection" !
Miracle, ça fonctionne !

Par contre j'ai essayé d'ajouté "fill selection" et là ça ne fonctionne pas, ça viens surement du fait que je n'ai jamais codé de ma vie et que c'est du bidouillage complet !

Si un oeil expert pouvais regarder au code, je lui en serais très reconnaissant :

var op = doc->GetActiveObject(); if(!op)return;


if(!IsCommandChecked(1011192) && !IsCommandChecked(1011180))
CallCommand(1011192); // Loop Selection
else if(IsCommandChecked(1011192)) {
CallCommand(1011180); // Ring Selection
} else if(IsCommandChecked(1011180)) {
CallCommand(1011179); // Outline Selection
} else if(IsCommandChecked(1011179)) {
CallCommand(1011178); // Fill Selection
} else CallCommand(1011192); // Loop Selection

Sir Gong
09/01/2015, 16h46
aucune idée, mais je t'ai passé membre reconnu et déplacé le sujet...

Sunlight84
09/01/2015, 17h49
Merci beaucoup Sir Gong,

Je vais faire un petit récapitulatif :

Le but de ce sujet est de réussir à créer des scripts permettant de basculer entre des outils ou des attributs d'outils à l'aide d'une seule touche.

Jusqu'ici les scripts suivant fonctionnent :

( Pour les faire fonctionner suivez les conseils de oli_d :
Ouvrir le gestionnaire de scripts, ensuite choisir l'onglet COFFEE, puis Fichier/Nouveau (dans le menu du gestionnaire de script) puis coller le code et boutonexécuter )

Basculer entre les sous-objets -Model-, -Points-, -Edges- et -Polygons- :
var op = doc->GetActiveObject(); if(!op)return;


if(!IsCommandChecked(12298) && !IsCommandChecked(12139) && !IsCommandChecked(16351))
CallCommand(12298); // Model
else if(IsCommandChecked(12298)) {
CallCommand(12139); // Points
} else if(IsCommandChecked(12139)) {
CallCommand(16351); // Edges
} else if(IsCommandChecked(16351)) {
CallCommand(12187); // Polygons
} else return;

Basculer entre les outils -Bridge-, -Slide- et -Stitch & Sew- :


var op = doc->GetActiveObject(); if(!op)return;


if(!IsCommandChecked(450000008) && !IsCommandChecked(450000012))
CallCommand(450000008); // Bridge
else if(IsCommandChecked(450000008)) {
CallCommand(450000012); // Slide
} else if(IsCommandChecked(450000012)) {
CallCommand(450000011); // Stitch and Sew
} else return;

Basculer entre l'option -line et -loop- du Knife :

if(!IsCommandChecked(1016030) || tool()#MDATA_KNIFE_MODE != 0) {
CallCommand(1016030); // Knife
tool()#MDATA_KNIFE_MODE = 0;
} else {
tool()#MDATA_KNIFE_MODE = 2;
tool()#MDATA_KNIFE_RESTRICT = FALSE;
}

Il reste encore à élucider comment ajouter les options -Path- et -Plane- au script de l'outils Knife

Basculer entre -extrude-, -extrude Inner- et -Bevel- :

var op = doc->GetActiveObject(); if(!op)return;


if(!IsCommandChecked(1011183) && !IsCommandChecked(450000004))
CallCommand(1011183); // Extrude
else if(IsCommandChecked(1011183)) {
CallCommand(450000004); // Extrude Inner
} else if(IsCommandChecked(450000004)) {
CallCommand(431000015); // Bevel
} else return;

Basculer entre -Loop selection-, -Ring selection-, -Outline selection- et Path selection

var op = doc->GetActiveObject(); if(!op)return;


if(!IsCommandChecked(1011192) && !IsCommandChecked(1011180) && !IsCommandChecked(1011179))
CallCommand(1011192); // Loop Selection
else if(IsCommandChecked(1011192)) {
CallCommand(1011180); // Ring Selection
} else if(IsCommandChecked(1011180)) {
CallCommand(1011179); // Outline Selection
} else if(IsCommandChecked(1011179)) {
CallCommand(1012129); // Path Selection
} else return;

Floc
09/01/2015, 22h56
Hello
Tant qu'à faire il vaudrait mieux repartir sur du python plus simple et plus utilisé maintenant.
Comme c'est à ma portée je t'ai fait une conversion du toggle "Bridge, Slide et Stitch & Sew" et des options line, loop etc... du knife.
Il y a les cinq options, par contre j'ai pas réussi à le refaire comme le coffee, c'est donc moins "élégant", mais apparement ça marche.

Bridge, Slide et Stitch & Sew


import c4d
from c4d import gui

def main():
c4d.CallCommand(13957) # Clear Console


if( not c4d.IsCommandChecked(450000008) and (not c4d.IsCommandChecked(450000012)) ):
c4d.CallCommand(450000008) #Bridge
elif( c4d.IsCommandChecked(450000008) ):
c4d.CallCommand(450000012) #Slide
elif( c4d.IsCommandChecked(450000012) ):
c4d.CallCommand(450000011) #Stitch and Sew
else:
c4d.CallCommand(450000008) #Bridge

c4d.EventAdd() #pas trop sur si cette ligne est nécessaire


if __name__=='__main__':
main()



Options Knife


import c4d
from c4d import gui

tool = doc.GetActiveToolData

def main():
c4d.CallCommand(13957) # Clear Console

if(not c4d.IsCommandChecked(1016030) ):
c4d.CallCommand(1016030) # Knife
if( (tool()[c4d.MDATA_KNIFE_MODE] == 0) ):
tool()[c4d.MDATA_KNIFE_MODE] = 1
elif( (tool()[c4d.MDATA_KNIFE_MODE] == 1) ):
tool()[c4d.MDATA_KNIFE_MODE] = 2
elif( (tool()[c4d.MDATA_KNIFE_MODE] == 2) ):
tool()[c4d.MDATA_KNIFE_MODE] = 3
elif( (tool()[c4d.MDATA_KNIFE_MODE] == 3) ):
tool()[c4d.MDATA_KNIFE_MODE] = 4
else:
tool()[c4d.MDATA_KNIFE_MODE] = 0
tool()[c4d.MDATA_KNIFE_RESTRICT] = False
else:
if( (tool()[c4d.MDATA_KNIFE_MODE] == 0) ):
tool()[c4d.MDATA_KNIFE_MODE] = 1
elif( (tool()[c4d.MDATA_KNIFE_MODE] == 1) ):
tool()[c4d.MDATA_KNIFE_MODE] = 2
elif( (tool()[c4d.MDATA_KNIFE_MODE] == 2) ):
tool()[c4d.MDATA_KNIFE_MODE] = 3
elif( (tool()[c4d.MDATA_KNIFE_MODE] == 3) ):
tool()[c4d.MDATA_KNIFE_MODE] = 4
else:
tool()[c4d.MDATA_KNIFE_MODE] = 0
tool()[c4d.MDATA_KNIFE_RESTRICT] = False

c4d.EventAdd()

if __name__=='__main__':
main()

oli_d
10/01/2015, 12h05
Super Floc,

Mais je pense qu'il y a encore quelques lignes inutiles et que l'on peut simplifier :


import c4d

def main():

if c4d.IsCommandChecked(450000008) :
c4d.CallCommand(450000012) #Slide
elif c4d.IsCommandChecked(450000012) :
c4d.CallCommand(450000011) #Stitch and Sew
else:
c4d.CallCommand(450000008) #Bridge


if __name__=='__main__':
main()

et


import c4d

def main():

if not c4d.IsCommandChecked(1016030) :
c4d.CallCommand(1016030) # Knife

tool = doc.GetActiveToolData()

if tool[c4d.MDATA_KNIFE_MODE] == 0 :
tool[c4d.MDATA_KNIFE_MODE] = 1
elif tool[c4d.MDATA_KNIFE_MODE] == 1 :
tool[c4d.MDATA_KNIFE_MODE] = 2
elif tool[c4d.MDATA_KNIFE_MODE] == 2 :
tool[c4d.MDATA_KNIFE_MODE] = 3
elif tool[c4d.MDATA_KNIFE_MODE] == 3 :
tool[c4d.MDATA_KNIFE_MODE] = 4
else:
tool[c4d.MDATA_KNIFE_MODE] = 0

c4d.EventAdd()

if __name__=='__main__':
main()

Mais on pourrait encore simplifier en utilisant une liste dans les deux cas, j'essaie de faire un p'tit tut minute c'est un bon exemple pour commencer le python ...


Ensuite, tu disais "Le second fonctionne sans autre ..." je ne comprends pas bien ce que tu as voulu dire, pourrais-tu développer ?
Tu penses que ce n'est pas possible d'ajouter le mode "plane" et "path" au script ?

J'avais lu ton post trop vite je croyais qu'il ne fonctionnait pas du tout

oli_d
10/01/2015, 17h17
Petit exercice de style pour que cela soit plus facilement modifiable. Il suffit de modifier,ajouter,supprimer des éléments de la liste au début.

Avec le code commenté :


# -*- coding: utf8 -*-
import c4d

def main():
#on crée la liste avec tous les outils dans l'ordre ou l'on veut qu'ils apparaisent
#pour savoir le no des outils, utiliser soit l'historique de script dans le menu script
#ensuite appeler n'importe quelle commande normalement, le no et le nom s'afficheront

#sinon utiliser Fenêtre/Interface/Personnaliser les commandes
#sélectionner la commande souhaitée et son no s'affiche en bas à droite de la fenêtre

lst = [ 450000008, #Bridge
450000012, #Slide
450000011] #Stitch and Sew

#identifiant de l'outil actif
id_tool = doc.GetAction()
#si l'outil actif n'est pas dans la liste on active le premier de la liste
if doc.GetAction() not in lst:
doc.SetAction(lst[0])
#sinon on prend le suivant dans la liste
else:
#on regarde quel est la position dans la liste de l'outil actif et on rajoute 1 pour le suivant
i = lst.index(id_tool) + 1
#si c'et le dernier on prend le premier
if i>=len(lst) : i = 0
#et on active l'outil en le recuperant dans la liste
doc.SetAction(lst[i])
#pour signaler à c4d qu'il y a eu un événement pour la mise à jour de la vue et de l'interface'
c4d.EventAdd()

if __name__=='__main__':
main()

Sans les commentaires et en résumant un peu on obtient 4 lignes de code !
C'est moins lisible, il y a une petite subtilité pour récupérer l'élément suivant de la liste (exercice pour faire chauffer les neurones ...)

import c4d

if __name__=='__main__':

lst = [ 450000008, 450000012, 450000011]
if doc.GetAction() not in lst: doc.SetAction(lst[0])
else: doc.SetAction(lst[(lst.index(doc.GetAction()) + 1) % len(lst)])
c4d.EventAdd()

et pour les paramètres de l'outil couteau, sur les mêmes principes ( et en utilisant les constantes de Cinema4D au lieu de 0,1,2,3,4):

import c4d

def main():

if not doc.GetAction() == 1016030 :
doc.SetAction(1016030) # Knife

tool = doc.GetActiveToolData()

lst = [ c4d.MDATA_KNIFE_MODE_SINGLE,
c4d.MDATA_KNIFE_MODE_MULTI,
c4d.MDATA_KNIFE_MODE_LOOP,
c4d.MDATA_KNIFE_MODE_PLANE,
c4d.MDATA_KNIFE_MODE_PATH ]

if tool[c4d.MDATA_KNIFE_MODE] in lst :
i = lst.index(tool[c4d.MDATA_KNIFE_MODE])
tool[c4d.MDATA_KNIFE_MODE] = lst[(i+1) % len(lst)]
else :
tool[c4d.MDATA_KNIFE_MODE] = lst[0]

c4d.EventAdd()

if __name__=='__main__':
main()

Sunlight84
11/01/2015, 14h23
Wow !! Il y a eu du mouvement pendant mon absence !

Tout d'abord un grand merci à toi Floc pour avoir pris le temps de lire tout ça et d'en plus convertir le code depuis COFFEE vers Python.
Tu règles en même temps mon soucis d'ajouter les autres options du Knife et c'est un soulagement.

Ensuite un tout grand merci à toi aussi oli_d pour prendre le temps de regarder en profondeur le problème et y ajouter ton expérience !

J'avoue que la dernière version du code, même avec ton tuto ( merci de prendre le temps de faire ça ), reste un mystère pour moi qui n'ai jamais codé quoique ce soit !

Tu m'as lancé quelques pistes que je vais étudier cet après midi.
Si j'arrive à adapter ta solution de liste aux autres outils et options d'outils qui me seraient utiles je n'hésite pas à poster tout ça ici !

Encore merci à tous !

Floc
11/01/2015, 16h48
@Oli_d
Merci pour ces version nettement plus pythonesque. :biggrin:

@Sunlight84
Pour comprendre les version condensées, et que l'on est un codeur du dimanche, il faut les redevelloper (Mais c'est ce qui est deja fait dans le tuto)

Voici ce que j'ai fait pour piger la ligne qui est dans else



else:
actionNum = doc.GetAction() # on recupere l'ID de la propriété actuelle
currentActionIdx = lst.index(actionNum) + 1 # on en deduit son n° dans la liste et on l'incrémente
action_idx = lst[currentActionIdx % len(lst)] # on recupere la propriété a appliquer dans la liste (le modulo permet de retourner à 0 quand l'incrementation depasse 4)
doc.SetAction(action_idx) # et on l'applique



@Oli_d
Est ce que les versions avec un code très concis était plutot pour illustrer le "python style" ou est ce que ce type de code est plus efficace.
C'est vrai que perso vu que je ne met pas le nez très souvent dans le code. j'ai tendance à l'étaler de façon à le rendre plus compréhensible.

et du coup j'ai deux autres petites questions
- J'avais trouvé la syntaxe pour utiliser tool sur le net sans me poser de question, mais la je viens de tilter que tool n'est qu'un baseContainer que retourne GetActiveToolData. Or j'utilisais tool comme une fonction et ça fonctionnais. Est ce qu'il y a une double syntaxe possible ?

- je ne comprend pas bien le sens de la ligne
if tool[c4d.MDATA_KNIFE_MODE] in lst :
Si je comprend bien c'est une boucle for dans un if.
Et l'expression "tool[c4d.MDATA_KNIFE_MODE] in lst" ne sera vrai que si le mode n'est pas "plane".
Donc si le mode est "plane" on passe sur else et on assigne "plane", sinon on assigne un des autres mode.

Pourquoi ne pas avoir simplement ecrit :
if not "mode plane"
assigner d'autre modes

César Vonc
11/01/2015, 20h35
- je ne comprend pas bien le sens de la ligne
if tool[c4d.MDATA_KNIFE_MODE] in lst :

Faut le comprendre comme en français (enfin, en anglais) : « Si la variable est dans la liste ».


if tool[c4d.MDATA_KNIFE_MODE] in lst : # Si le mode de l'outil est compris dans la liste :
i = lst.index(tool[c4d.MDATA_KNIFE_MODE]) # On cherche l'index de ce mode dans la liste
tool[c4d.MDATA_KNIFE_MODE] = lst[(i+1) % len(lst)] # Et l'outil vaut le mode suivant de la liste
else :
tool[c4d.MDATA_KNIFE_MODE] = lst[0] # Sinon l'outil vaut le premier mode de la liste


Utilisez les balises php plutôt que code, c'est plus joli. :P

Floc
11/01/2015, 23h16
Faut le comprendre comme en français (enfin, en anglais) : « Si la variable est dans la liste ».


Ah ben oui lu comme ça c'est effectivement plus simple.

Décidément j'ai des difficultés avec les facilités de python ! :whistling:

oli_d
12/01/2015, 07h28
Utilisez les balises php plutôt que code, c'est plus joli. :P

Tu as raison, c'est modifié (je n'ai pas le bouton pour mettre directement les balises PHP mais il me semble qu'un jour j'ai réussi à personnaliser tout ça et je ne sais plus comment...)


Est ce que les versions avec un code très concis était plutot pour illustrer le "python style" ou est ce que ce type de code est plus efficace.
C'est vrai que perso vu que je ne met pas le nez très souvent dans le code. j'ai tendance à l'étaler de façon à le rendre plus compréhensible.

Je ne pense pas qu'il y ait une quelconque incidence sur le temps d'exécution. C'était juste pour montrer que le script est relativement simple, parceque si un débutant le voit avec tout les commentaires il risque de partir en courant (bon je sais qu'il y en a quand même 99% qui sont partis en courant !)

Et tu as raison l'important c'est que le code reste lisible, il faut que tu puisses facilement le comprendre même si tu le reprends trois mois après. Donc au début c'est juste de bien l'étaler, mais avec l'habitude on a tendance à condenser. Et je te rassure je suis aussi un codeur du dimanche.


et du coup j'ai deux autres petites questions
- J'avais trouvé la syntaxe pour utiliser tool sur le net sans me poser de question, mais la je viens de tilter que tool n'est qu'un baseContainer que retourne GetActiveToolData. Or j'utilisais tool comme une fonction et ça fonctionnais. Est ce qu'il y a une double syntaxe possible ?

si tu écris : tool = doc.GetActiveTool (sans les parenthèses), tu récupères la méthode elle-même (ou la fonction), tu ne l'exécutes pas. C'est un peu comme si tu lui donnais un autre nom. Après si tu veux l'utiliser tu es obligé d'écrire tool() (avec parenthèses) ce qui exécutera la méthode et dans ce cas tu récupères la BaseContainer.

si j'écris tool = doc.GetActiveTool() je lance directement la méthode et tool récupère le résultat (dans ce cas un BaseContainer). Fais des tests avec print.


Pourquoi ne pas avoir simplement ecrit :
if not "mode plane"
assigner d'autre modes

César t'a très bien expliqué la première partie de la question. C'est vrai que dans ce cas précis on aurait pu faire plus simple, mais si je veux que mon script passe simplement du mode boucle au mode linéaire car c'est les deux modes que j'utilise le plus, avec ma méthode je modifie uniquement le tableau.

Math1712
12/01/2015, 08h04
Très instructifs ces commentaires dans le code ! Merci Oli et César :icon_clap:

Floc
13/01/2015, 05h17
Yep, Merci pour tout ces éclaircissements.