Bonjour,
Est-ce qu'un programmeur saurait pondre un petit script ou autre pour espacer régulièrement une sélection de points selon un axe ?
Par exemple sur l'image ci-dessous, que les points sélectionnés soient espacés régulièrement horizontalement, sans changer de position verticalement. (ou avec l'option de le faire aussi verticalement avec une case à cocher?)
Aucune idée de la difficulté de la tâche, mais si jamais c'était pas trop galère à mettre en œuvre, ce serait bien pratique.
÷ R19 Studio ÷ cacahuètes ÷
Salut Sir Gong.
Essaie de coller ça dans le gestionnaire de script, ça devrait te dépanner si t'en as besoin rapidement :
Tu peux changer l'espacement et l'axe au début.
Code PHP:
import c4d
from c4d import Vector
def main():
#
espace = 10.0
axe = "-z"
# Axe à changer par : x, -x, y, -y, z ou -z
#
if not op : return
if not op.CheckType(c4d.Opoint) : return
inv = False
if (axe[0] == "-") :
inv = True
axe = axe[1:]
axeVec = Vector(0,1,1)
posAxe = Vector(espace,0,0)
if axe == "y" :
axeVec = Vector(1,0,1)
posAxe = Vector(0,espace,0)
elif axe == 'z' :
axeVec = Vector(1,1,0)
posAxe = Vector(0,0,espace)
doc.StartUndo()
doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
pts = []
bs = op.GetPointS()
for i, sel in enumerate(bs.GetAll(op.GetPointCount())) :
if not sel : continue
posv = op.GetPoint(i)
pos = posv.x
if axe == "y" : pos = posv.y
elif axe == 'z' : pos = posv.z
pts.append((pos, i))
pts.sort()
if inv : pts.reverse()
posCum = op.GetPoint(pts[0][1]).__rxor__(posAxe.GetNormalized())
if inv : posAxe *= -1
for pt in pts :
i = pt[1]
pos = op.GetPoint(i)
pos = pos.__rxor__(axeVec) + posCum
op.SetPoint(i, pos)
posCum += posAxe
op.Message(c4d.MSG_UPDATE)
doc.EndUndo()
c4d.EventAdd()
if __name__=='__main__':
main()
Merci beaucoup César,
Si je comprends bien (rien n'est moins sûr), je dois renseigner la valeur de l'espace et l'axe (lignes 6 et 7) avant de l'éxécuter.
Est-ce qu'il est possible, au lieu de donner une valeur d'espacement, que le script trouve lui même la valeur à répartir entre le 1er et le dernier point sélectionnés ?
Enfin, là ça me dépanne déjà bien, j'obtiens un espacement régulier, et il me suffit ensuite d'entrer une valeur de la taille pour redimensionner l'ensemble de la sélection. Merci encore.
÷ R19 Studio ÷ cacahuètes ÷
Bonjour Sir Gong si j'ai bien compris la valeur = la distance entre le premier et le dernier point sur l'axe / par le nombre de points c'est ça ?
mmh, en gros c'est ce qu'on retrouve avec l'outil "alignement" d'illustrator mais appliqué à des points. ça peut s'avérer très utile ça
La chance sourit aux audacieux : pourvu qu’elle n’ait pas de caries.
http://yoniverse.jimdo.com/
Je me suis permis une variante qui prend la vue active comme référence et répartit sur l'axe horizontal de la vue entre le point le plus à gauche et le plus à droite.
Code PHP:
import c4d
def main():
#on vérifie que l'on est bien en mode point
if not doc.GetMode() ==c4d.Mpoints : return
#on vérifie si il y a bien un objet sélectionné ...
if not op : return
#et si cet objet est de type point (spline ou objet polygonal)
if not op.CheckType(c4d.Opoint) : return
#on récupère le BaseSelect des points
bs = op.GetPointS()
mg = op.GetMg()
#on récupère la fenêtre de dessin active
bd = doc.GetActiveBaseDraw()
dico_ptsvue = {}
pts_vueX = []
for i,sel in enumerate(bs.GetAll(op.GetPointCount())) :
if not sel: continue
pt_vue = bd.WS(op.GetPoint(i)*mg)
dico_ptsvue[i] = pt_vue
pts_vueX.append((pt_vue.x,i))
pts_vueX.sort()
id_pt_depart = pts_vueX[1]
dist = (pts_vueX[-1][0]-pts_vueX[0][0])/(len(pts_vueX)-1)
posX = pts_vueX[0][0]
inv_mg = ~mg
doc.StartUndo()
doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
for x,i in pts_vueX:
pt_vue = dico_ptsvue[i]
pt_vue.x = posX
pt = bd.SW(pt_vue)*inv_mg
op.SetPoint(i,pt)
posX+=dist
op.Message(c4d.MSG_UPDATE)
doc.EndUndo()
c4d.EventAdd()
if __name__=='__main__':
main()
Dernière modification par oli_d ; 06/02/2015 à 09h46.
@ Math1712 : oui, c'est ça.
@ leBigYO : voilà, c'est exactement ça.
Utile, mais ce n'est pas le genre de truc dont on a besoin tous les jours. Généralement les outils de C4D (pinceau en mode lissage, ponçage) suffisent, mais pour le cas présent le lissage bouge les points adjacents, ce qui ne va pas.
@ oli_d : merci, ça marche impec, maintenant il faudrait une case à cocher ou je ne sais quoi pour choisir l'axe et ne pas avoir à tourner la géométrie et ce serait parfait.
÷ R19 Studio ÷ cacahuètes ÷
Pff en plus il fait ça en 15 lignes, Oli_d. ^^
Bien joué !
Merci César, mais il y en a un peu plus que 15 ...
@Sir Gong : plutôt qu'une case à cocher je te mets le code ci-dessous pour la répartition verticale selon la vue. Si tu te fais ensuite deux boutons, un avec le vertical, l'autre l'horizontal, est-ce que cela suffirait à te combler de bonheur ?
Code PHP:
import c4d
def main():
if not doc.GetMode() ==c4d.Mpoints : return
if not op : return
if not op.CheckType(c4d.Opoint) : return
bs = op.GetPointS()
mg = op.GetMg()
bd = doc.GetActiveBaseDraw()
dico_ptsvue = {}
pts_vueY = []
for i,sel in enumerate(bs.GetAll(op.GetPointCount())) :
if not sel: continue
pt_vue = bd.WS(op.GetPoint(i)*mg)
dico_ptsvue[i] = pt_vue
pts_vueY.append((pt_vue.y,i))
pts_vueY.sort()
id_pt_depart = pts_vueY[1]
dist = (pts_vueY[-1][0]-pts_vueY[0][0])/(len(pts_vueY)-1)
posY = pts_vueY[0][0]
inv_mg = ~mg
doc.StartUndo()
doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
for x,i in pts_vueY:
pt_vue = dico_ptsvue[i]
pt_vue.y = posY
pt = bd.SW(pt_vue)*inv_mg
op.SetPoint(i,pt)
posY+=dist
op.Message(c4d.MSG_UPDATE)
doc.EndUndo()
c4d.EventAdd()
if __name__=='__main__':
main()
C'est parfait, oli-d merci beaucoup !
(et à César aussi pour la 1ere mouture)
÷ R19 Studio ÷ cacahuètes ÷