Voir la version complète : Python - Doc Utilitaires
César Vonc
08/10/2017, 12h29
Salut,
Je vous propose une classe Utilitaire Python concoctée au fur et à mesure du temps, vous y trouverez des fonctions de modélisation en tout genre, des calculs informations sur un objet polygonal, des conversion de sélection...
Certaines utilisent les SendModelingCommand, d'autres non (l'idée est à terme de ne plus avoir à se servir des commandes).
Certaines de ces fonctions sont assez précieuses, d'autres que j'utilise tout le temps, j'espère que ça en aidera à développer de nouveaux outils ! :biggrin:
N'hésitez pas si vous avez des remarques, des suggestions, du café, il manque encore la fonction de Biseautage (elle déconne un peu). :sweatdrop:
Sommaire
Calculs sur un objet
CalculeNormalesPolys
CalculeNormalesPoints
CalculeNormalesPointsPolys
CalculeCentrePolys
CalculeDecentreBruitPolys
CalculeNombreAretesPolys
CalculeAirePolys
CalculeAirePolysFacteur
CalculePerimetrePolys
CalculeOrthocentreTriangles
CalculeNbPolysParPoint
CalculePointsBordureListe
CalculePointsBordureMarquage
CalculePointsBordureSelectMarquage
CalculeAretes
DictionnaireAretes
CalculeAretesBordure
CalculeAretesBordureAvecPolys
CalculePolysBordureMarquage
CalculePointPolysTries
CalculeLiaisonPoints
CalculeGroupesParPoly
BruitPoints
Calculs géométriques
VolumeTetraedre
AirePolygone
PerimetrePolygone
OrthocentreTriangle
Modification d'un objet
BruiteObjet
LissageCatmullClark
RecopieObjet
Optimiser
AlignerNormales
InverserNormales
Trianguler
Quadranguler
Subdiviser
FermerTrous
BiseauterCommande
BiseauterC4D
Biseauter
ExtruderC4D
Extruder
ReductionDePolys
SupprimerPolygones
Opérations sur les polygones
AreteOpposee
AreteAdjacente
ListeAretesPolygone
ListeAretesPolygoneSensABCD
Opérations sur les matrices
TransposeMatrice
Opérations sur les vecteurs
RefleteVecteur
IntersectionSegments2DBool
IntersectionSegments2DVector
IntersectionDroites2DBool
IntersectionDroites2DVector
Sélections
BaseSelectAretesToutes
BaseSelectPolysDepuisAretes
BaseSelectPolysTous
SelectionnePointsTous
SelectionnePointsPolysPoints
SelectionnePolysTous
SelectionnePolysInverse
SelectionnePolysAucun
SelectionneAretesToutes
SelectionneAretesInverse
SelectionneAretesAucune
SelectionneAretesContour
MarquagePointsDepuisAretes
AffichePolysTous
AffichePointsTous
AfficheAretesToutes
Débug (http://frenchcinema4d.fr/showthread.php?81877-Python-Doc-Utilitaires&p=1074425&viewfull=1#post1074425)
DebugVecteur
DebugTexte
Vous pouvez retrouver ou télécharger la classe ici : http://code.vonc.fr/?a=100
César Vonc
08/10/2017, 12h30
Calculs sur un objet
CalculeNormalesPolys
http://code.vonc.fr/details/100/image_CalculeNormalesPolys.png
def CalculeNormalesPolys(obj) :
"""
Calcule les normales des polys de l'objet.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de Vector) - Liste des normales
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPolys = obj.GetPolygonCount()
norPolys = [c4d.Vector()] * nbPolys
nor = c4d.Vector()
for i, poly in enumerate(polys) :
nor = (pts[poly.a] - pts[poly.c]).Cross(pts[poly.b] - pts[poly.d])
nor.Normalize()
norPolys[i] = nor
return norPolys
CalculeNormalesPoints
http://code.vonc.fr/details/100/image_CalculeNormalesPoints.png
def CalculeNormalesPoints(obj, bsPolys = None) :
"""
Calcule les normales des points de l'objet.
Paramètres :
obj (PolygonObject) - Objet
bsPolys (BaseSelect) - Sélection de polygones pour limiter le calcul des normales des points
Renvoie :
(liste de Vector) - Liste des normales
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPoints = obj.GetPointCount()
norPts = [c4d.Vector()] * nbPoints
if bsPolys is None :
for i, poly in enumerate(polys) :
normale = (pts[poly.a] - pts[poly.c]).Cross(pts[poly.b] - pts[poly.d])
normale.Normalize()
norPts[poly.a] += normale
norPts[poly.b] += normale
norPts[poly.c] += normale
if (poly.c != poly.d) : norPts[poly.d] += normale
else :
nbPolys = obj.GetPolygonCount()
bsTous = bsPolys.GetAll(nbPolys)
for i, sel in enumerate(bsTous) :
if not sel : continue
poly = polys[i]
normale = (pts[poly.a] - pts[poly.c]).Cross(pts[poly.b] - pts[poly.d])
normale.Normalize()
norPts[poly.a] += normale
norPts[poly.b] += normale
norPts[poly.c] += normale
if (poly.c != poly.d) : norPts[poly.d] += normale
for i in xrange(nbPoints) :
norPts[i].Normalize()
return norPts
CalculeNormalesPointsPolys
http://code.vonc.fr/details/100/image_CalculeNormalesPointsPolys.png
def CalculeNormalesPointsPolys(obj, bsPolys = None) :
"""
Calcule les normales des points et des polys de l'objet.
Paramètres :
obj (PolygonObject) - Objet
bsPolys (BaseSelect) - Sélection de polygones pour limiter le calcul des normales
Renvoie :
(liste de Vector) - Liste des normales des points
(liste de Vector) - Liste des normales des polys
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPoints = obj.GetPointCount()
nbPolys = obj.GetPolygonCount()
norPts = [c4d.Vector()] * nbPoints
norPolys = [c4d.Vector()] * nbPolys
if bsPolys is None :
for i, poly in enumerate(polys) :
normale = (pts[poly.a] - pts[poly.c]).Cross(pts[poly.b] - pts[poly.d])
normale.Normalize()
norPolys[i] = normale
norPts[poly.a] += normale
norPts[poly.b] += normale
norPts[poly.c] += normale
if (poly.c != poly.d) : norPts[poly.d] += normale
else :
nbPolys = obj.GetPolygonCount()
bsTous = bsPolys.GetAll(nbPolys)
for i, sel in enumerate(bsTous) :
if not sel : continue
poly = polys[i]
normale = (pts[poly.a] - pts[poly.c]).Cross(pts[poly.b] - pts[poly.d])
normale.Normalize()
norPolys[i] = normale
norPts[poly.a] += normale
norPts[poly.b] += normale
norPts[poly.c] += normale
if (poly.c != poly.d) : norPts[poly.d] += normale
for i in xrange(nbPoints) :
norPts[i].Normalize()
return norPts, norPolys
CalculeCentrePolys
http://code.vonc.fr/details/100/image_CalculeCentrePolys.png
def CalculeCentrePolys(obj) :
"""
Calcule le centre des polys de l'objet.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de Vector) - Liste des positions
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPolys = obj.GetPolygonCount()
centrePolys = [c4d.Vector()] * nbPolys
centre = c4d.Vector()
for i, poly in enumerate(polys) :
if poly.c != poly.d :
centre = (pts[poly.a] + pts[poly.b] + pts[poly.c] + pts[poly.d]) / 4.
else :
centre = (pts[poly.a] + pts[poly.b] + pts[poly.c]) / 3.
centrePolys[i] = centre
return centrePolys
CalculeDecentreBruitPolys
http://code.vonc.fr/details/100/image_CalculeDecentreBruitPolys.png
def CalculeDecentreBruitPolys(obj, intensite = 1.0, temps = 0.0, echelle = 1.0) :
"""
Calcule un point dans le polys de l'objet à partir d'un facteur de bruit.
Paramètres :
obj (PolygonObject) - Objet
intensite (float) - Intensité du bruit
temps (float) - Temps
echelle (float) - Échelle du bruit
Renvoie :
(liste de Vector) - Liste des positions
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPolys = obj.GetPolygonCount()
bruit = c4d.utils.noise.Noise
mixVec = c4d.utils.MixVec
centrePolys = [c4d.Vector()] * nbPolys
centre = c4d.Vector()
decentre = c4d.Vector()
pos = c4d.Vector()
for i, poly in enumerate(polys) :
a = pts[poly.a]
b = pts[poly.b]
c = pts[poly.c]
d = pts[poly.d]
if poly.c != poly.d :
centre = (a + b + c + d) / 4.
pos = centre * echelle
n = bruit(pos, temps)
m = bruit(pos + 9999., temps)
decentre = a * (n * .5) + c * ((1. - n) * .5) + b * (m * .5) + d * ((1. - m) * .5)
decentre = mixVec(centre, decentre, intensite)
else :
centre = (a + b + c) / 3.
pos = centre * echelle
n = bruit(pos, temps)
m = bruit(pos + 9999., temps)
d = (a + b) * .5
decentre = a * (n * .5) + b * ((1. - n) * .5) + c * (m * .5) + d * ((1. - m) * .5)
decentre = mixVec(centre, decentre, intensite)
centrePolys[i] = decentre
return centrePolys
CalculeNombreAretesPolys
http://code.vonc.fr/details/100/image_CalculeNombreAretesPolys.png
def CalculeNombreAretesPolys(obj) :
"""
Calcule le nombre d'arête de chaque polys.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de int) - Liste d'entiers
"""
polys = obj.GetAllPolygons()
nbPolys = obj.GetPolygonCount()
nbAretesPolys = [0] * nbPolys
for i, pol in enumerate(polys) :
nbAretesPolys[i] = 3 if pol.c == pol.d else 4
return nbAretesPolys
CalculeAirePolys
http://code.vonc.fr/details/100/image_CalculeAirePolys.png
def CalculeAirePolys(obj) :
"""
Calcule l'aire de tous les polys.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de float) - Liste des aires
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPolys = obj.GetPolygonCount()
aires = [0.] * nbPolys
AirePolygone = VoncUtils.AirePolygone
for i, pol in enumerate(polys) :
aires[i] = AirePolygone(pol, pts)
return aires
CalculeAirePolysFacteur
http://code.vonc.fr/details/100/image_CalculeAirePolysFacteur.png
def CalculeAirePolysFacteur(obj) :
"""
Calcule un facteur de taille de 0 à 1 pour chaque poly par rapport à leur aire.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de float) - Liste de flottants de 0.0 à 1.0
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPolys = obj.GetPolygonCount()
aires = [0.] * nbPolys
mini = 0.
maxi = 0.
AirePolygone = VoncUtils.AirePolygone
sqrt = math.sqrt
for i, pol in enumerate(polys) :
aire = sqrt(AirePolygone(pol, pts))
aires[i] = aire
if i == 0 :
mini = aire
maxi = aire
else :
if aire < mini : mini = aire
if aire > maxi : maxi = aire
diff = maxi - mini
if abs(diff) <= 0.000001 : return [1.] * nbPolys
for i, aire in enumerate(aires) :
aires[i] = (aire - mini) / diff
return aires
CalculePerimetrePolys
http://code.vonc.fr/details/100/image_CalculePerimetrePolys.png
def CalculePerimetrePolys(obj) :
"""
Calcule le périmètre de tous les polys.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de float) - Liste des périmètres
"""
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
nbPolys = obj.GetPolygonCount()
perims = [0.] * nbPolys
PerimetrePolygone = VoncUtils.PerimetrePolygone
for i, pol in enumerate(polys) :
perims[i] = PerimetrePolygone(pol, pts)
return perims
CalculeOrthocentreTriangles
http://code.vonc.fr/details/100/image_CalculeOrthocentreTriangles.png
def CalculeOrthocentreTriangles(obj) :
"""
Calcule l'orthocentre des triangles de l'objet, à supposer que tous les polys sont des triangles.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de Vector) - Liste des positions
"""
nbTriangles = obj.GetPolygonCount()
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
orthoPolys = [c4d.Vector()] * nbTriangles
for i, poly in enumerate(polys) :
a = pts[poly.a]
b = pts[poly.b]
c = pts[poly.c]
orthoPolys[i] = VoncUtils.OrthocentreTriangle(a, b, c)
return orthoPolys
CalculeNbPolysParPoint
http://code.vonc.fr/details/100/image_CalculeNbPolysParPoint.png
def CalculeNbPolysParPoint(obj, bsPolys = None) :
"""
Calcule le nombre de polygones autour de chaque point.
Paramètres :
obj (PolygonObject) - Objet
bsPolys (BaseSelect) - Sélection de polygones pour limiter le calcul
Renvoie :
(liste de int) - Liste d'entiers
"""
polys = obj.GetAllPolygons()
nbPts = obj.GetPointCount()
nbPolysParPts = [0] * nbPts
if bsPolys is None :
for poly in polys :
nbPolysParPts[poly.a] += 1
nbPolysParPts[poly.b] += 1
nbPolysParPts[poly.c] += 1
if (poly.c != poly.d) :
nbPolysParPts[poly.d] += 1
else :
nbPolys = obj.GetPolygonCount()
bsTous = bsPolys.GetAll(nbPolys)
for i, sel in enumerate(bsTous) :
if not sel : continue
poly = polys[i]
nbPolysParPts[poly.a] += 1
nbPolysParPts[poly.b] += 1
nbPolysParPts[poly.c] += 1
if (poly.c != poly.d) :
nbPolysParPts[poly.d] += 1
return nbPolysParPts
CalculePointsBordureListe
http://code.vonc.fr/details/100/image_CalculePointsBordureListe.png
def CalculePointsBordureListe(obj, bsPolys = None) :
"""
Calcule la liste des points qui constituent la bordure de l'objet.
Paramètres :
obj (PolygonObject) - Objet
bsPolys (BaseSelect) - Sélection de polygones pour limiter le calcul
Renvoie :
(liste de int) - Liste d'indices des points de bordure
"""
polys = obj.GetAllPolygons()
ptsBordure = []
liaisonPts = VoncUtils.CalculeLiaisonPoints(obj, bsPolys)
nbPolysParPts = VoncUtils.CalculeNbPolysParPoint(obj, bsPolys)
for i, npol in enumerate(nbPolysParPts) :
npt = len(liaisonPts[i])
if (npt != npol and npol != 0) :
ptsBordure.append(i)
return ptsBordure
CalculePointsBordureMarquage
http://code.vonc.fr/details/100/image_CalculePointsBordureMarquage.png
def CalculePointsBordureMarquage(obj, bsPolys = None) :
"""
Calcule le tableau de marquage des points qui constituent la bordure de l'objet.
Paramètres :
obj (PolygonObject) - Objet
bsPolys (BaseSelect) - Sélection de polygones pour limiter le calcul
Renvoie :
(liste de bool) - Liste de booléens marquants les points de bordure
"""
polys = obj.GetAllPolygons()
nbPts = obj.GetPointCount()
ptsBordure = [False] * nbPts
liaisonPts = VoncUtils.CalculeLiaisonPoints(obj, bsPolys)
nbPolysParPts = VoncUtils.CalculeNbPolysParPoint(obj, bsPolys)
for i, npol in enumerate(nbPolysParPts) :
npt = len(liaisonPts[i])
if (npt != npol) :
ptsBordure[i] = True
return ptsBordure
CalculePointsBordureSelectMarquage
http://code.vonc.fr/details/100/image_CalculePointsBordureSelectMarquage.png
def CalculePointsBordureSelectMarquage(obj, bs, n = None) :
"""
Calcule le tableau de marquage des points qui constituent la bordure de la sélection du BaseSelect.
Paramètres :
obj (PolygonObject) - Objet
bs (BaseSelect) - Sélection de polygones pour limiter le calcul
n (Neighbor) - Neighbor initialisé avec le BaseSelect
Renvoie :
(liste de bool) - Liste de booléens marquants les points de bordure
"""
nbPolys = obj.GetPolygonCount()
nbPts = obj.GetPointCount()
polys = obj.GetAllPolygons()
if n is None :
n = c4d.utils.Neighbor()
n.Init(obj, bs)
ptsBords = [False] * nbPts
for i, sel in enumerate(bs.GetAll(nbPolys)) :
if sel :
poly = polys[i]
vois = n.GetNeighbor(poly.a, poly.b, i)
if vois == c4d.NOTOK :
ptsBords[poly.a] = True
ptsBords[poly.b] = True
vois = n.GetNeighbor(poly.b, poly.c, i)
if vois == c4d.NOTOK :
ptsBords[poly.b] = True
ptsBords[poly.c] = True
vois = n.GetNeighbor(poly.d, poly.a, i)
if vois == c4d.NOTOK :
ptsBords[poly.d] = True
ptsBords[poly.a] = True
if poly.c != poly.d :
vois = n.GetNeighbor(poly.c, poly.d, i)
if vois == c4d.NOTOK :
ptsBords[poly.c] = True
ptsBords[poly.d] = True
return ptsBords
CalculeAretes
http://code.vonc.fr/details/100/image_CalculeAretes.png
def CalculeAretes(obj) :
"""
Calcule la liste des arêtes de l'objet. Une arête est un couple de deux indices de points, le premier inférieur au second.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de tuple(int, int)) - Liste d'arêtes, une arête étant un tuple de deux ID de points, trié.
"""
aretes = []
aretesDico = {}
polys = obj.GetAllPolygons()
for pol in polys :
areAB = (pol.a, pol.b)
if (pol.b < pol.a) : areAB = (pol.b, pol.a)
aretesDico[areAB] = True
areBC = (pol.b, pol.c)
if (pol.c < pol.b) : areBC = (pol.c, pol.b)
aretesDico[areBC] = True
if pol.c == pol.d :
areCA = (pol.c, pol.a)
if (pol.a < pol.c) : areCA = (pol.a, pol.c)
aretesDico[areCA] = True
else :
areCD = (pol.c, pol.d)
if (pol.d < pol.c) : areCD = (pol.d, pol.c)
aretesDico[areCD] = True
areDA = (pol.d, pol.a)
if (pol.a < pol.d) : areDA = (pol.a, pol.d)
aretesDico[areDA] = True
aretes = aretesDico.keys()
return aretes
DictionnaireAretes
http://code.vonc.fr/details/100/image_DictionnaireAretes.png
def DictionnaireAretes(obj) :
"""
Renvoie le dictionnaire des arêtes de l'objet.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(dictionnaire de tuple(int, int)) - Dictionnaire avec les arêtes comme clef et None comme valeur, une arête étant un tuple de deux ID de points, trié.
"""
aretesDico = {}
polys = obj.GetAllPolygons()
for pol in polys :
areAB = (pol.a, pol.b)
if (pol.b < pol.a) : areAB = (pol.b, pol.a)
aretesDico[areAB] = None
areBC = (pol.b, pol.c)
if (pol.c < pol.b) : areBC = (pol.c, pol.b)
aretesDico[areBC] = None
if pol.c == pol.d :
areCA = (pol.c, pol.a)
if (pol.a < pol.c) : areCA = (pol.a, pol.c)
aretesDico[areCA] = None
else :
areCD = (pol.c, pol.d)
if (pol.d < pol.c) : areCD = (pol.d, pol.c)
aretesDico[areCD] = None
areDA = (pol.d, pol.a)
if (pol.a < pol.d) : areDA = (pol.a, pol.d)
aretesDico[areDA] = None
return aretesDico
CalculeAretesBordure
http://code.vonc.fr/details/100/image_CalculeAretesBordure.png
def CalculeAretesBordure(obj, n = None) :
"""
Calcule la liste des arêtes de bordure de l'objet.
Paramètres :
obj (PolygonObject) - Objet
n (Neighbor) - Neighbor initialisé
Renvoie :
(liste de tuple(int, int)) - Liste d'arêtes de bordure, une arête étant un tuple de deux ID de points, trié.
"""
aretes = []
polys = obj.GetAllPolygons()
if n is None :
n = c4d.utils.Neighbor()
n.Init(obj)
for i, pol in enumerate(polys) :
nab = n.GetNeighbor(pol.a, pol.b, i)
nbc = n.GetNeighbor(pol.b, pol.c, i)
nda = n.GetNeighbor(pol.d, pol.a, i)
if nab == c4d.NOTOK :
are = (pol.a, pol.b) if pol.a < pol.b else (pol.b, pol.a)
aretes.append(are)
if nbc == c4d.NOTOK :
are = (pol.b, pol.c) if pol.b < pol.c else (pol.c, pol.b)
aretes.append(are)
if nda == c4d.NOTOK :
are = (pol.d, pol.a) if pol.d < pol.a else (pol.a, pol.d)
aretes.append(are)
if pol.c != pol.d :
ncd = n.GetNeighbor(pol.c, pol.d, i)
if ncd == c4d.NOTOK :
are = (pol.c, pol.d) if pol.c < pol.d else (pol.d, pol.c)
aretes.append(are)
return aretes
CalculeAretesBordureAvecPolys
http://code.vonc.fr/details/100/image_CalculeAretesBordureAvecPolys.png
def CalculeAretesBordureAvecPolys(obj, n = None, bsPolys = None) :
"""
Calcule la liste des arêtes de bordure de l'objet, avec l'id du poly pour chaque arête.
Paramètres :
obj (PolygonObject) - Objet
n (Neighbor) - Neighbor initialisé avec le BaseSelect
bsPolys (BaseSelect) - Sélection de polygones pour délimiter la zone
Renvoie :
(liste de tuple(int, int, int)) - Liste d'arêtes avec ID du polygone, une arête étant un tuple de deux ID de points, trié.
"""
aretes = []
polys = obj.GetAllPolygons()
nbPolys = obj.GetPolygonCount()
if n is None :
n = c4d.utils.Neighbor()
n.Init(obj, bsPolys)
def calculeBord(n, pol, i, aretes) :
nab = n.GetNeighbor(pol.a, pol.b, i)
nbc = n.GetNeighbor(pol.b, pol.c, i)
nda = n.GetNeighbor(pol.d, pol.a, i)
if nab == c4d.NOTOK :
are = (pol.a, pol.b, i) if pol.a < pol.b else (pol.b, pol.a, i)
aretes.append(are)
if nbc == c4d.NOTOK :
are = (pol.b, pol.c, i) if pol.b < pol.c else (pol.c, pol.b, i)
aretes.append(are)
if nda == c4d.NOTOK :
are = (pol.d, pol.a, i) if pol.d < pol.a else (pol.a, pol.d, i)
aretes.append(are)
if pol.c != pol.d :
ncd = n.GetNeighbor(pol.c, pol.d, i)
if ncd == c4d.NOTOK :
are = (pol.c, pol.d, i) if pol.c < pol.d else (pol.d, pol.c, i)
aretes.append(are)
if bsPolys is None :
for i, pol in enumerate(polys) :
calculeBord(n, pol, i, aretes)
else :
bsTous = bsPolys.GetAll(nbPolys)
for i, sel in enumerate(bsTous) :
if sel : calculeBord(n, polys[i], i, aretes)
return aretes
CalculePolysBordureMarquage
http://code.vonc.fr/details/100/image_CalculePolysBordureMarquage.png
def CalculePolysBordureMarquage(obj) :
"""
Calcule le tableau de marquage des polys qui déterminent la bordure de l'objet.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(liste de bool) - Liste de booléens marquants les polys qui constituent la bordure de l'objet.
"""
polysBord = [False] * obj.GetPolygonCount()
polys = obj.GetAllPolygons()
n = c4d.utils.Neighbor()
n.Init(obj)
for i, pol in enumerate(polys) :
nab = n.GetNeighbor(pol.a, pol.b, i)
nbc = n.GetNeighbor(pol.b, pol.c, i)
nda = n.GetNeighbor(pol.d, pol.a, i)
if nab == c4d.NOTOK :
polysBord[i] = True
if nbc == c4d.NOTOK :
polysBord[i] = True
if nda == c4d.NOTOK :
polysBord[i] = True
if pol.c != pol.d :
ncd = n.GetNeighbor(pol.c, pol.d, i)
if ncd == c4d.NOTOK :
polysBord[i] = True
return polysBord
CalculePointPolysTries
http://code.vonc.fr/details/100/image_CalculePointPolysTries.png
def CalculePointPolysTries(obj, nei = None) :
"""
Calcule les polygones attachés à chaque point, triés par sens horaire.
Paramètres :
obj (PolygonObject) - Objet
nei (Neighbor) - Neighbor initialisé
Renvoie :
(liste de liste de int) - Liste des ID des polygones autour de chaque point, triés par sens horaire.
"""
if nei is None :
nei = c4d.utils.Neighbor()
nei.Init(obj)
nbPts = obj.GetPointCount()
polys = obj.GetAllPolygons()
pts = obj.GetAllPoints()
pointsPolys = [None] * nbPts
for i in xrange(nbPts) :
polsDuPt = nei.GetPointPolys(i)
if not polsDuPt :
pointsPolys[i] = []
continue
nbVois = len(polsDuPt)
polsDuPtTrie = []
pol = polsDuPt[0]
polDeb = pol
arete = None
inverser = False
autreAreteDebut = False
k = 0
while k < nbVois + 1 :
polsDuPtTrie.append(pol)
poly = polys[pol]
# icentre est le point i, iexts sont les deux autres points du poly, situés après et avant icentre (par ordre abcd)
icentre = poly.a
iexts = (poly.b, poly.d) # a, suivant : b, précédent : d (c = d pour triangle)
if poly.b == i :
icentre = poly.b
iexts = (poly.c, poly.a) # b, suivant : c, précédent : a
elif poly.c == i :
icentre = poly.c
if poly.c != poly.d :
iexts = (poly.d, poly.b) # (pour quadrangle) c, suivant : d, précédent : b
else :
iexts = (poly.a, poly.b) # (pour triangle) c, suivant : a, précédent : b
elif poly.d == i :
icentre = poly.d
iexts = (poly.a, poly.c) # (pour quadrangle exclusivement) b, suivant : a, précédent : c
if k == 0 or autreAreteDebut :
# Pour le premier poly, prendre l'arête du point qui suit l'ordre abcd du poly (nécessite les normales alignées)
arete = (icentre, iexts[0])
if autreAreteDebut :
arete = (icentre, iexts[1])
else :
# Prendre une arête du poly qui ne soit pas celle précédemment choisie
arete = (icentre, iexts[0]) if iexts[0] != arete[1] else (icentre, iexts[1])
prem, sec = nei.GetEdgePolys(arete[0], arete[1])
# Trouver le voisin qui ne soit pas égal au premier poly ni au poly précédemment ajouté
if prem != c4d.NOTOK or sec != c4d.NOTOK :
if prem != polDeb and prem != pol and prem != c4d.NOTOK :
pol = prem
elif sec != polDeb and sec != pol and sec != c4d.NOTOK :
pol = sec
else :
if k == 0 :
# Dans le cas du premier poly ajouté, si le sens choisi donne sur un bord, parcourir dans l'autre sens puis inverser le résultat et supprimer le doublon du premier poly.
pol = pol
polsDuPtTrie.pop()
inverser = True
else :
if len(polsDuPtTrie) != nbVois :
# S'il manque des polys, c'est qu'on a commencé par une arête d'un poly sans arête de bordure, et qu'on est tombé sur une bordure prématurément
# Dans ce cas, partir dans l'autre sens à partir du poly de départ, mais avec l'autre arête.
# Inverser le tableau actuel pour que l'ajout se fasse dans le bon ordre, puis réinverser le tout.
polsDuPtTrie.reverse()
_deb = polsDuPtTrie.pop()
inverser = True
autreAreteDebut = True
pol = polDeb
polDeb = _deb
else :
break
else :
break
k += 1
if not inverser :
polsDuPtTrie.reverse()
pointsPolys[i] = polsDuPtTrie
return pointsPolys
CalculeLiaisonPoints
http://code.vonc.fr/details/100/image_CalculeLiaisonPoints.png
def CalculeLiaisonPoints(obj, bsPolys = None) :
"""
Calcule la liste des points voisins de chaque point.
Paramètres :
obj (PolygonObject) - Objet
bsPolys (BaseSelect) - Sélection de polygones pour délimiter la zone
Renvoie :
(liste de liste de int) - Liste des ID des points autour de chaque point.
"""
nbPts = obj.GetPointCount()
polys = obj.GetAllPolygons()
liaisonPts = [None] * nbPts
for i in xrange(nbPts) :
liaisonPts[i] = set()
if bsPolys is None :
for poly in polys :
liaisonPts[poly.a].add(poly.d)
liaisonPts[poly.a].add(poly.b)
liaisonPts[poly.b].add(poly.a)
liaisonPts[poly.b].add(poly.c)
if (poly.c != poly.d) :
# Quadrangle
liaisonPts[poly.c].add(poly.b)
liaisonPts[poly.c].add(poly.d)
liaisonPts[poly.d].add(poly.c)
liaisonPts[poly.d].add(poly.a)
else :
# Triangle
liaisonPts[poly.c].add(poly.b)
liaisonPts[poly.c].add(poly.a)
else :
nbPolys = obj.GetPolygonCount()
bsTous = bsPolys.GetAll(nbPolys)
for i, sel in enumerate(bsTous) :
if not sel : continue
poly = polys[i]
liaisonPts[poly.a].add(poly.d)
liaisonPts[poly.a].add(poly.b)
liaisonPts[poly.b].add(poly.a)
liaisonPts[poly.b].add(poly.c)
if (poly.c != poly.d) :
# Quadrangle
liaisonPts[poly.c].add(poly.b)
liaisonPts[poly.c].add(poly.d)
liaisonPts[poly.d].add(poly.c)
liaisonPts[poly.d].add(poly.a)
else :
# Triangle
liaisonPts[poly.c].add(poly.b)
liaisonPts[poly.c].add(poly.a)
for i in xrange(nbPts) :
liaisonPts[i] = tuple(liaisonPts[i])
return liaisonPts
CalculeGroupesParPoly
http://code.vonc.fr/details/100/image_CalculeGroupesParPoly.png
def CalculeGroupesParPoly(obj):
"""
Calcule pour chaque poly l'ID du groupe de polygones auquel il appartient
Paramètres :
(PolygonObject) - Objet
Renvoie :
(liste de int) - Liste d'ID de groupe pour chaque polygone
(int) - Nombre de groupes
"""
if not obj : return None, None
nbPolys = obj.GetPolygonCount()
polys = obj.GetAllPolygons()
polysGroupe = [-1] * nbPolys
nbGroupes = 0
n = c4d.utils.Neighbor()
n.Init(obj)
for i, g in enumerate(polysGroupe) :
if g != -1 : continue
polysATraiter = [i]
while(polysATraiter) :
polysATraiterSuivant = []
for p in polysATraiter :
polysGroupe[p] = nbGroupes
for p in polysATraiter :
poly = polys[p]
voisA = n.GetNeighbor(poly.a, poly.b, p)
voisB = n.GetNeighbor(poly.b, poly.c, p)
voisD = n.GetNeighbor(poly.d, poly.a, p)
voisC = c4d.NOTOK
if poly.c != poly.d :
voisC = n.GetNeighbor(poly.c, poly.d, p)
if voisA != c4d.NOTOK and polysGroupe[voisA] == -1 :
polysATraiterSuivant.append(voisA)
if voisB != c4d.NOTOK and polysGroupe[voisB] == -1 :
polysATraiterSuivant.append(voisB)
if voisC != c4d.NOTOK and polysGroupe[voisC] == -1 :
polysATraiterSuivant.append(voisC)
if voisD != c4d.NOTOK and polysGroupe[voisD] == -1 :
polysATraiterSuivant.append(voisD)
polysATraiter = list(set(polysATraiterSuivant))
nbGroupes += 1
return polysGroupe, nbGroupes
BruitPoints
http://code.vonc.fr/details/100/image_BruitPoints.png
def BruitPoints(obj, intensite = 1.0, temps = 0.0, echelle = 1.0) :
"""
Renvoie une valeur aléatoire pour chaque point de l'objet.
Paramètres :
obj (PolygonObject) - Objet
intensite (float) - Intensité du bruit
temps (float) - Temps
echelle (float) - Échelle du bruit
Renvoie :
(liste de float) - Liste de flottants, de 0.0 à 1.0
"""
nbPts = obj.GetPointCount()
pts = obj.GetAllPoints()
bruit = [0.] * nbPts
if nbPts == 0 : return bruit
noise = c4d.utils.noise.Noise
mixVec = c4d.utils.MixVec
for i in xrange(nbPts) :
bruit[i] = noise(pts[i] * echelle, temps) * intensite
return bruit
César Vonc
08/10/2017, 12h31
Calculs géométriques
VolumeTetraedre
def VolumeTetraedre(p1, p2, p3) :
"""
Calcule le volume d'un tétraèdre.
Paramètres :
p1 (Vector) - Position du premier point
p2 (Vector) - Position du second point
p3 (Vector) - Position du troisième point
Renvoie :
(float) - Volume
"""
return p1.Dot(p2.Cross(p3)) / 6.0
AirePolygone
def AirePolygone(pol, pts) :
"""
Calcule l'aire d'un polygone.
Paramètres :
pol (CPolygon) - Polygone
pts (liste de Vector) - Points de l'objet
Renvoie :
(float) - Aire
"""
a = pts[pol.a]
b = pts[pol.b]
c = pts[pol.c]
if pol.IsTriangle() :
return (a - b).Cross(a - c).GetLength() * 0.5
d = pts[pol.d]
ac = a - c
return ((a - b).Cross(ac).GetLength() + (ac).Cross(a - d).GetLength()) * 0.5
PerimetrePolygone
def PerimetrePolygone(pol, pts) :
"""
Calcule le périmètre d'un polygone.
Paramètres :
pol (CPolygon) - Polygone
pts (liste de Vector) - Points de l'objet
Renvoie :
(float) - Périmètre
"""
a = pts[pol.a]
b = pts[pol.b]
c = pts[pol.c]
if pol.IsTriangle() :
return (a - b).GetLength() + (b - c).GetLength() + (c - a).GetLength()
d = pts[pol.d]
return (a - b).GetLength() + (b - c).GetLength() + (c - d).GetLength() + (d - a).GetLength()
OrthocentreTriangle
def OrthocentreTriangle(a, b, c) :
"""
Calcule l'orthocentre d'un triangle 3D.
Paramètres :
a (Vector) - Premier point
b (Vector) - Second point
c (Vector) - Troisième point
Renvoie :
(Vector ou None) - Orthocentre
"""
ab = b - a
bc = c - b
cb = b - c
abn = ab.GetNormalized()
bcn = bc.GetNormalized()
mab = abn.Dot(c - a) * abn + a
mbc = bcn.Dot(a - b) * bcn + b
n = (a - c).Cross(cb)
hab = ab.Cross(n)
hbc = (cb).Cross(n)
m = c4d.utils.HPBToMatrix(c4d.utils.VectorToHPB(n))
m.off = b
mi = ~m
hab = mi.Mul(hab)
hbc = mi.Mul(hbc)
mab = mi.Mul(mab)
mbc = mi.Mul(mbc)
inter = VoncUtils.IntersectionDroites2DVector(mab, mab + hab, mbc, mbc + hbc)
if inter is None :
return None
inter = m.Mul(inter)
return inter
César Vonc
08/10/2017, 12h32
Modification d'un objet
BruiteObjet
http://code.vonc.fr/details/100/image_BruiteObjet.png
def BruiteObjet(obj, intensite = 1.0, temps = 0.0, echelle = 1.0) :
"""
Déforme les points d'un objet le long de ses arêtes de façon aléatoire.
Paramètres :
obj (PolygonObject) - Objet
intensite (float) - Intensité du bruit
temps (float) - Temps
echelle (float) - Échelle du bruit
"""
nbPts = obj.GetPointCount()
pts = obj.GetAllPoints()
pts2 = [c4d.Vector()] * nbPts
if nbPts == 0 : return
liaisonPts = VoncUtils.CalculeLiaisonPoints(obj)
bruit = c4d.utils.noise.Noise
mixVec = c4d.utils.MixVec
for i in xrange(nbPts) :
ptsVois = liaisonPts[i] # Points autour du point
nbPtsVois = len(ptsVois)
pt = pts[i]
pt2 = c4d.Vector()
for vois in ptsVois :
n = bruit(pts[vois] * echelle, temps) * 2. - 1.
pt2 += mixVec(pt, pts[vois], n)
pt2 /= float(nbPtsVois)
pts2[i] = mixVec(pt, pt2, intensite)
obj.SetAllPoints(pts2)
obj.Message(c4d.MSG_UPDATE)
LissageCatmullClark
http://code.vonc.fr/details/100/image_LissageCatmullClark.png
def LissageCatmullClark(obj, intensite = 1.0, influence = None, nei = None, bsPolys = None) :
"""
Lisse les points de l'objet basé sur la méthode Catmull-Clark.
Paramètres :
intensite (float) - Facteur d'intensité du lissage (0.0 à 1.0).
influence (liste de float) - Facteur d'intensité du lissage pour chaque point.
nei (Neihbor) - Neighbor initialisé avec le BaseSelect.
bsPolys (BaseSelect) - Sélection de polygones pour limiter l'effet.
"""
if nei is None :
nei = c4d.utils.Neighbor()
nei.Init(obj, bsPolys)
nbPts = obj.GetPointCount()
pts = obj.GetAllPoints()
if nbPts == 0 : return
ptsNouv = [c4d.Vector()] * nbPts
liaisonPts = VoncUtils.CalculeLiaisonPoints(obj, bsPolys)
centrePolys = VoncUtils.CalculeCentrePolys(obj)
for i in xrange(nbPts) :
polsVois = nei.GetPointPolys(i) # Polys autour du point
nbPolsVois = len(polsVois)
ptsVois = liaisonPts[i] # Points liés au point i
nbPtsVois = len(ptsVois)
if not nbPolsVois or not nbPtsVois :
ptsNouv[i] = pts[i]
continue
pmaBord = [] # Point de Milieu d'Arête de Bordure
po = pts[i] # Point Original
pos = c4d.Vector() # Nouvelle position
if nbPtsVois != nbPolsVois : # Bordure
if nbPtsVois != nbPolsVois + 1 : # Point avec plus de 2 bordures
pos = po
else :
pmaMoy = c4d.Vector()
nbBord = 0
for j in ptsVois :
prem, sec = nei.GetEdgePolys(i, j)
if prem == c4d.NOTOK or sec == c4d.NOTOK :
pmaMoy += (po + pts[j]) * .5
nbBord += 1
pmaMoy /= float(nbBord)
pos = (po + pmaMoy) * .5
else :
nbPolsVois = float(nbPolsVois)
nbPtsVois = float(nbPtsVois)
# Moyenne des Point de Surface
psMoy = c4d.Vector()
for j in polsVois :
psMoy += centrePolys[j]
psMoy /= nbPolsVois
# Moyenne des Points d'Arête
pmaMoy = c4d.Vector()
for j in ptsVois :
pmaMoy += (po + pts[j]) * .5
pmaMoy /= nbPtsVois
# Catmull-Clark
pos = psMoy + (2.0 * pmaMoy) + ((nbPolsVois - 3.0) * po);
pos /= nbPolsVois
ptsNouv[i] = pos
for i, ptNouv in enumerate(ptsNouv) :
if influence :
pts[i] = ptNouv * intensite * influence[i] + (pts[i] * (1. - intensite * influence[i]))
else :
pts[i] = ptNouv * intensite + (pts[i] * (1. - intensite))
obj.SetAllPoints(pts)
obj.Message(c4d.MSG_UPDATE)
RecopieObjet
def RecopieObjet(src, dest) :
"""
Recopie les données polygonales d'un objet vers un autre.
Paramètres :
src (PolygonObject) - Objet source
dest (PolygonObject) - Objet de destination
Renvoie :
(bool) - Booléen, succès ou non
"""
nouvNbPts = src.GetPointCount()
nouvNbPolys = src.GetPolygonCount()
nouvPts = src.GetAllPoints()
nouvPolys = src.GetAllPolygons()
if nouvNbPts == 0 :
return False
dest.ResizeObject(nouvNbPts, nouvNbPolys)
dest.Message(c4d.MSG_UPDATE)
dest.SetAllPoints(nouvPts)
for i, p in enumerate(nouvPolys) :
dest.SetPolygon(i, p)
dest.Message(c4d.MSG_UPDATE)
return True
Optimiser
def Optimiser(obj, doc, polys = True, pts = True, ptsiso = True, tolerance = 0.01) :
"""
Optimiser.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
polys (bool) - Optimiser les polygones
pts (bool) - Optimiser les points
ptsiso (bool) - Optimiser les points isolés
tolerance (float) - Tolérance d'optimisation des points
"""
params = c4d.BaseContainer()
params[c4d.MDATA_OPTIMIZE_TOLERANCE] = tolerance
params[c4d.MDATA_OPTIMIZE_POINTS] = pts
params[c4d.MDATA_OPTIMIZE_POLYGONS] = polys
params[c4d.MDATA_OPTIMIZE_UNUSEDPOINTS] = ptsiso
c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _OPTIMIZE, list=[obj], bc=params, doc=doc)
AlignerNormales
def AlignerNormales(obj, doc) :
"""
Aligner les normales.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
Renvoie :
(bool) - Succès ou non
"""
return c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _ALIGNNORMALS, list=[obj], doc=doc)
InverserNormales
def InverserNormales(obj, doc) :
"""
Inverser les normales.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
Renvoie :
(bool) - Succès ou non
"""
return c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _REVERSENORMALS, list=[obj], doc=doc)
Trianguler
def Trianguler(obj, doc) :
"""
Convertit les polygones en triangles.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
Renvoie :
(bool) - Succès ou non
"""
return c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _TRIANGULATE, list=[obj], doc=doc)
Quadranguler
def Quadranguler(obj, doc) :
"""
Convertit les triangles en quadrangles.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
Renvoie :
(bool) - Succès ou non
"""
bc = c4d.BaseContainer()
bc[c4d.MDATA_UNTRIANGULATE_NGONS] = False
bc[c4d.MDATA_UNTRIANGULATE_ANGLE_RAD] = .1 * (math.pi / 180.)
bc[c4d.MDATA_UNTRIANGULATE_ANGLE] = False
return c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _UNTRIANGULATE, list=[obj], bc=bc, doc=doc)
Subdiviser
http://code.vonc.fr/details/100/image_Subdiviser.png
def Subdiviser(obj, doc, iterations = 1, catmullClark = True, selectionActive = False, bs = None) :
"""
Subdivise les polygones d'un objet.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
iterations (int) - Nombre d'itération de la subdivision
catmullClark (bool) - Active ou non la subdivision de type Catmull-Clark
selectionActive (bool) - Utilise ou non la sélection de polygone courante
bs (BaseSelect) - Sélection de polygones pour limiter la subdivision
Renvoie :
(bool) - Succès ou non
"""
bc = c4d.BaseContainer()
bc[c4d.MDATA_SUBDIVIDE_HYPER] = catmullClark
bc[c4d.MDATA_SUBDIVIDE_ANGLE] = math.pi
bc[c4d.MDATA_SUBDIVIDE_SUB] = iterations
mode = c4d.MODELINGCOMMANDMODE_ALL
if selectionActive :
mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION
if bs is not None :
mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION
bsc = bs.GetClone()
bs = obj.GetPolygonS()
bs.DeselectAll()
bs.Merge(bsc)
return c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _SUBDIVIDE, list=[obj], mode=mode, bc=bc, doc=doc)
FermerTrous
http://code.vonc.fr/details/100/image_FermerTrous.png
def FermerTrous(obj, doc) :
"""
Ferme tous les trous d'un objet.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
"""
polys = obj.GetAllPolygons()
n = c4d.utils.Neighbor()
n.Init(obj)
params = c4d.BaseContainer()
params[c4d.MDATA_CLOSEHOLE_INDEX] = obj
params[c4d.MDATA_CLOSEHOLE_TRI] = True
mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION
commande = c4d.ID_MODELING_CLOSEHOLE_TOOL
SendModelingCommand = c4d.utils.SendModelingCommand
for i, pol in enumerate(polys) :
nab = n.GetNeighbor(pol.a, pol.b, i)
nbc = n.GetNeighbor(pol.b, pol.c, i)
ncd = n.GetNeighbor(pol.c, pol.d, i)
nda = n.GetNeighbor(pol.d, pol.a, i)
cotes = n.GetPolyInfo(i)["edge"]
if nab == c4d.NOTOK :
params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[0]
SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
n.Init(obj)
if nbc == c4d.NOTOK :
params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[1]
SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
n.Init(obj)
if ((ncd == c4d.NOTOK) and (pol.c != pol.d)) :
params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[2]
SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
n.Init(obj)
if nda == c4d.NOTOK :
params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[3]
SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
n.Init(obj)
obj.Message(c4d.MSG_UPDATE)
BiseauterCommande
def BiseauterCommande(obj, doc, rayon = 0., mode = "chanfrein", subdivision = 0, limite = False) :
"""
Biseaute la sélection d'arêtes courante, en utilisant CallCommand.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
rayon (float) - Rayon du biseau
mode (string) - Mode du biseau ('chanfrein' ou 'solide')
subdivision (int) - Subdivision
limite (bool) - Limite le rayon du biseau
"""
mmode = doc.GetMode()
doc.SetMode(c4d.Medges)
c4d.CallCommand(431000015, 431000015)
tool = c4d.plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL)
if tool is not None :
tool[c4d.MDATA_BEVEL_LIMIT] = limite
tool[c4d.MDATA_BEVEL_SUB] = subdivision
tool[c4d.MDATA_BEVEL_RADIUS] = rayon
tool[c4d.MDATA_BEVEL_MASTER_MODE] = c4d.MDATA_BEVEL_MASTER_MODE_CHAMFER
if mode == "solide" :
tool[c4d.MDATA_BEVEL_MASTER_MODE] = c4d.MDATA_BEVEL_MASTER_MODE_SOLID
c4d.CallButton(tool, c4d.MDATA_APPLY)
doc.SetMode(mmode)
BiseauterC4D
def BiseauterC4D(obj, doc, bs, rayon = 0., mode = "chanfrein", subdivision = 0, limite = False) :
"""
Biseaute une sélection d'arêtes, en utilisant le déformateur Biseau. Renvoie l'objet biseauté.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
bs (BaseSelect) - Sélection d'arêtes
rayon (float) - Rayon du biseau
mode (string) - Mode du biseau ('chanfrein' ou 'solide')
subdivision (int) - Subdivision
limite (bool) - Limite le rayon du biseau
Renvoie :
(BaseObject ou None) - Objet biseauté
"""
# Propriété Sélection d'arêtes
propSelAretes = obj.MakeTag(c4d.Tedgeselection)
propSelAretes.SetName("SelAreBiseau")
bsAre = propSelAretes.GetBaseSelect()
bsAre.Merge(bs)
# Déformateur Biseau
defBiseau = c4d.BaseObject(431000028)
defBiseau[c4d.O_BEVEL_MODE_COMPONENT_TYPE] = c4d.O_BEVEL_MODE_COMPONENT_TYPE_EDGE
defBiseau[c4d.O_BEVEL_RESTRICTION_START] = propSelAretes.GetName()
if mode == "solide" : defBiseau[c4d.O_BEVEL_MASTER_MODE] = c4d.O_BEVEL_MASTER_MODE_SOLID
else : defBiseau[c4d.O_BEVEL_MASTER_MODE] = c4d.O_BEVEL_MASTER_MODE_CHAMFER
defBiseau[c4d.O_BEVEL_RADIUS] = rayon
defBiseau[c4d.O_BEVEL_SUB] = subdivision
defBiseau[c4d.O_BEVEL_LIMIT] = limite
defBiseau.InsertUnder(obj)
res = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _CURRENTSTATETOOBJECT, list=[obj], doc=doc)
if res : doc.InsertObject(res[0])
propSelAretes.Remove()
defBiseau.Remove()
if res : return res[0]
return None
ExtruderC4D
def ExtruderC4D(obj, doc, decalage, capot = False, subdivision = 0, ngones = False, angle = 3.141592653589793) :
"""
Extrude les polygones sélectionnés avec la méthode de C4D.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
decalage (float) - Décalage de l'extrusion
capot (bool) - Créé ou non le capot
subdivision (int) - Subdivision de l'extrusion
ngones (bool) - Créé ou non des n-gones
angle (float) - Angle de limitation de cohésion des polygones extrudés
Renvoie :
(bool) - Succès ou non
"""
bc = c4d.BaseContainer()
bc[c4d.MDATA_EXTRUDE_PRESERVEGROUPS] = True
bc[c4d.MDATA_EXTRUDE_OFFSET ] = decalage
bc[c4d.MDATA_EXTRUDE_VARIANCE ] = 0.0
bc[c4d.MDATA_EXTRUDE_ANGLE ] = angle
bc[c4d.MDATA_EXTRUDE_SUBDIVISION ] = subdivision
bc[c4d.MDATA_EXTRUDE_CREATENGONS ] = ngones
bc[c4d.MDATA_EXTRUDE_CREATECAPS ] = capot
return c4d.utils.SendModelingCommand(command = c4d.ID_MODELING_EXTRUDE_TOOL,
list = [obj],
bc = bc,
mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
doc = doc)
Extruder
http://code.vonc.fr/details/100/image_Extruder.png
def Extruder(obj, decalage, capot = False, subdivision = 0, bs = None, normalesPts = None, extrusionBi = False, facteurDec = None) :
"""
Extrude les polygones. Renvoie le type de chaque polygone.
Paramètres :
obj (PolygonObject) - Objet
decalage (float) - Décalage de l'extrusion
capot (bool) - Créé ou non les polygones du capot
subdivision (int) - Subdivision de l'extrusion
bs (BaseSelect) - Sélection de polygones à extruder
normalesPts (liste de Vector) - Direction de l'extrusion pour chaque point
extrusionBi (bool) - Extrude vers l'avant et l'arriète
facteurDec (liste de float) - Intensité de l'extrusion pour chaque point
Renvoie :
(liste de int, ou None) - Liste d'entiers. Pour chaque polygone :
0 : Polygone original
1 : Face avant
2 : Tranche
3 : Face arrière
"""
if obj is None or not obj.CheckType(c4d.Opolygon) : return None
nbPts = obj.GetPointCount()
nbPolys = obj.GetPolygonCount()
pts = obj.GetAllPoints()
polys = obj.GetAllPolygons()
if bs is None :
bs = c4d.BaseSelect()
bs.SelectAll(nbPolys-1)
nbPolysSel = 0
nouvNbPolys = nbPolys
if not capot : extrusionBi = False
if extrusionBi : decalage *= .5
# Tableau pour les tableaux de marquage de retour
tableauSel = [0] * nbPolys # 0 : Polygones originaux
SEL_FACE_AVANT = 1 # Face avant
SEL_FACE_TRANCHE = 2 # Tranche
SEL_FACE_ARRIERE = 3 # Face arrière
if decalage > 0 and capot :
SEL_FACE_AVANT, SEL_FACE_ARRIERE = SEL_FACE_ARRIERE, SEL_FACE_AVANT
if facteurDec is not None and len(facteurDec) != nbPts :
facteurDec = None
if normalesPts is not None and len(normalesPts) != nbPts :
normalesPts = None
if normalesPts is None :
normalesPts = VoncUtils.CalculeNormalesPoints(obj, bs)
bsTout = bs.GetAll(nbPolys)
for i, sel in enumerate(bsTout) :
if sel :
nbPolysSel += 1
tableauSel[i] = SEL_FACE_AVANT
if nbPolysSel == 0 : return None
# Récupère les arêtes et les points de bordure
aretesBordPoly = VoncUtils.CalculeAretesBordureAvecPolys(obj, None, bs)
nbBords = len(aretesBordPoly) * (subdivision+1)
ptsBords = [False] * nbPts
for are in aretesBordPoly :
ptsBords[are[0]] = True
ptsBords[are[1]] = True
# Récupère les points à extruder et compte le nombre de polys attachés à eux
ptsAEx = [0] * nbPts
for i, sel in enumerate(bsTout) :
if not sel : continue
poly = polys[i]
ptsAEx[poly.a] += 1
ptsAEx[poly.b] += 1
ptsAEx[poly.c] += 1
if poly.c != poly.d : ptsAEx[poly.d] += 1
# Compte le nouveau nombre de points et créé la correspondance des anciens points vers ceux extrudés
nouvNbPts = nbPts
ancPtVersNouv = [0] * nbPts
for i, sel in enumerate(ptsAEx) :
# Si le point fait parti du base select des polys et, dans le cas sans capot, s'il fait parti des bords, le copier
if sel != 0 and (capot or ptsBords[i]) :
ancPtVersNouv[i] = nouvNbPts
nouvNbPts += 1
if subdivision and ptsBords[i] : # Bordure
nouvNbPts += subdivision
# Créé les nouveaux points
nouvPts = [c4d.Vector()] * (nouvNbPts - nbPts)
pts.extend(nouvPts)
for i, sel in enumerate(ptsAEx) :
if sel != 0 :
# Si bordure, prendre le point clone correspondant, sinon prendre le même qu'on bouge (cas sans capot)
j = i
if (capot or ptsBords[i]) : j = ancPtVersNouv[i]
facDec = decalage + 0.
if facteurDec is not None :
facDec *= facteurDec[i]
pts[j] = pts[i] + normalesPts[i] * facDec
if extrusionBi :
pts[i] = pts[i] - normalesPts[i] * facDec
if subdivision and ptsBords[i] : # Bordure
if not extrusionBi :
for k in xrange(subdivision) :
pts[j + k + 1] = pts[i] + normalesPts[i] * facDec * (1. - (k + 1.) / (subdivision + 1.))
else :
for k in xrange(subdivision) :
pts[j + k + 1] = pts[i] + normalesPts[i] * facDec * (1. - (k + 1.) / (subdivision + 1.)) * 2.
# Créé les polygones de tranche
j = nouvNbPolys
nouvNbPolys += nbBords
nouvPolys = [None] * nbBords
polys.extend(nouvPolys)
tableauSel.extend([SEL_FACE_TRANCHE] * nbBords)
for are in aretesBordPoly :
p0 = are[0]
p1 = are[1]
ipol = are[2]
pol = polys[ipol]
i0 = pol.Find(p0)
i1 = pol.Find(p1)
if pol.IsTriangle() :
if i0 == 3 : i0 = 2
if i1 == 3 : i1 = 2
if decalage > 0. or not capot :
if i0 == (i1 + 1) % 3:
p0, p1 = p1, p0
else :
if i1 == (i0 + 1) % 3:
p0, p1 = p1, p0
else :
if decalage > 0. or not capot :
if i0 == (i1 + 1) % 4:
p0, p1 = p1, p0
else :
if i1 == (i0 + 1) % 4:
p0, p1 = p1, p0
p2 = ancPtVersNouv[p1]
p3 = ancPtVersNouv[p0]
if subdivision :
for i in xrange(subdivision + 1) :
poly = c4d.CPolygon(
p0,
p1,
p2 + subdivision - i,
p3 + subdivision - i
)
polys[j] = poly
j += 1
p0 = poly.d
p1 = poly.c
else :
poly = c4d.CPolygon(
p0,
p1,
p2,
p3
)
polys[j] = poly
j += 1
aretesBordPoly = None
# Créé les nouveaux polygones extrudés
if capot :
j = nouvNbPolys
nouvNbPolys += nbPolysSel
nouvPolys = [None] * nbPolysSel
polys.extend(nouvPolys)
tableauSel.extend([SEL_FACE_ARRIERE] * nbPolysSel)
for i, sel in enumerate(bsTout) :
if not sel : continue
poly = polys[i]
nouvPoly = None
if decalage > 0. :
nouvPoly = c4d.CPolygon(
ancPtVersNouv[poly.a],
ancPtVersNouv[poly.b],
ancPtVersNouv[poly.c],
ancPtVersNouv[poly.d]
)
else :
nouvPoly = c4d.CPolygon(
ancPtVersNouv[poly.d],
ancPtVersNouv[poly.c],
ancPtVersNouv[poly.b],
ancPtVersNouv[poly.a]
)
polys[j] = nouvPoly
# tableauSel[j] = SEL_FACE_ARRIERE
j += 1
else :
for i, sel in enumerate(bsTout) :
if not sel : continue
poly = polys[i]
a = poly.a
b = poly.b
c = poly.c
d = poly.d
poly.a = ancPtVersNouv[a] if capot or ptsBords[a] else a
poly.b = ancPtVersNouv[b] if capot or ptsBords[b] else b
poly.c = ancPtVersNouv[c] if capot or ptsBords[c] else c
if c != d :
poly.d = ancPtVersNouv[d] if capot or ptsBords[d] else d
else :
poly.d = poly.c
# Si capot et décalage positif renverser les normales des polys du capot
if capot and decalage > 0. :
for i, sel in enumerate(bsTout) :
if not sel : continue
poly = polys[i]
a = poly.a
b = poly.b
c = poly.c
d = poly.d
if c != d :
poly.a = d
poly.b = c
poly.c = b
poly.d = a
else :
poly.a = b
poly.b = a
# Applique les nouvelles coordonnées
obj.ResizeObject(nouvNbPts, nouvNbPolys)
obj.SetAllPoints(pts)
for i, p in enumerate(polys) :
obj.SetPolygon(i, p)
obj.Message(c4d.MSG_UPDATE)
return tableauSel
ReductionDePolys
http://code.vonc.fr/details/100/image_ReductionDePolys.png
def ReductionDePolys(obj, doc, intensite, courbe = False) :
"""
Applique le déformateur Réduction de polygones.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
intensite (float) - Intensité de la réduction (de 0.0 à 1.0)
courbe (bool) - Préserve la délimitation
Renvoie :
(None ou BaseObject) - Objet réduit
"""
# Déformateur Biseau
defReduc = c4d.BaseObject(c4d.Opolyreduction)
defReduc[c4d.POLYREDUCTIONOBJECT_STRENGTH] = intensite
defReduc[c4d.POLYREDUCTIONOBJECT_BOUNDARY] = courbe
defReduc.InsertUnder(obj)
res = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND _CURRENTSTATETOOBJECT, list=[obj], doc=doc)
if res : doc.InsertObject(res[0])
defReduc.Remove()
if res : return res[0]
return None
SupprimerPolygones
def SupprimerPolygones(obj, doc) :
"""
Supprime la sélection de polygones courante.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
"""
c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_DELETE,
list = [obj],
mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
doc = doc)
César Vonc
08/10/2017, 12h33
Opérations sur les polygones
AreteOpposee
http://code.vonc.fr/details/100/image_AreteOpposee.png
def AreteOpposee(p0, p1, poly) :
"""
Renvoie l'arête opposée à deux points, ordonnée de façon symétrique aux points en paramètre.
Paramètres :
p0 (int) - ID du premier point de l'arête
p1 (int) - ID du second point de l'arête
poly (CPolygon) - Polygone concerné
Renvoie :
(tuple(int, int)) - ID du premier et du second point de l'arête opposée
"""
arete = poly.FindEdge(p0, p1)
if arete == c4d.NOTOK :
return (-1, -1)
if poly.c == poly.d : # Triangle
if p0 == poly.a :
if p1 == poly.b : return (poly.c, p1)
else : return (poly.b, p1)
elif p0 == poly.b :
if p1 == poly.a : return (poly.c, p1)
else : return (poly.a, p1)
else :
if p1 == poly.a : return (poly.b, p1)
else : return (poly.a, p1)
areteOpp = (arete + 2) % 4
ptsOpp = poly.EdgePoints(areteOpp)
if poly.FindEdge(p0, ptsOpp[0]) != c4d.NOTOK :
return (ptsOpp[0], ptsOpp[1])
else :
return (ptsOpp[1], ptsOpp[0])
AreteAdjacente
http://code.vonc.fr/details/100/image_AreteAdjacente.png
def AreteAdjacente(p0, p1, poly) :
"""
Renvoie l'arête adjacente à partir de deux points d'une arête.
Paramètres :
p0 (int) - ID du premier point de l'arête
p1 (int) - ID du second point de l'arête
poly (CPolygon) - Polygone concerné
Renvoie :
(tuple(int, int)) - ID du premier et du second point de l'arête adjacente, trié par ID
"""
if p0 == p1 : return (-1, -1)
if poly.IsTriangle() :
if p0 == poly.a :
if p1 == poly.c : return (poly.a, poly.b) if poly.a < poly.b else (poly.b, poly.a) # 0, 1
else : return (poly.a, poly.c) if poly.a < poly.c else (poly.c, poly.a) # 0, 2
elif p0 == poly.b :
if p1 == poly.a : return (poly.b, poly.c) if poly.b < poly.c else (poly.c, poly.b) # 1, 2
else : return (poly.a, poly.b) if poly.a < poly.b else (poly.b, poly.a) # 1, 0
else :
if p1 == poly.b : return (poly.a, poly.c) if poly.a < poly.c else (poly.c, poly.a) # 2, 0
else : return (poly.b, poly.c) if poly.b < poly.c else (poly.c, poly.b) # 2, 1
else :
if p0 == poly.a :
if p1 == poly.d : return (poly.a, poly.b) if poly.a < poly.b else (poly.b, poly.a) # 0, 1
else : return (poly.a, poly.d) if poly.a < poly.d else (poly.d, poly.a) # 0, 3
elif p0 == poly.b :
if p1 == poly.a : return (poly.b, poly.c) if poly.b < poly.c else (poly.c, poly.b) # 1, 2
else : return (poly.a, poly.b) if poly.a < poly.b else (poly.b, poly.a) # 1, 0
elif p0 == poly.c :
if p1 == poly.b : return (poly.c, poly.d) if poly.c < poly.d else (poly.d, poly.c) # 2, 3
else : return (poly.b, poly.c) if poly.b < poly.c else (poly.c, poly.b) # 2, 1
else :
if p1 == poly.c : return (poly.a, poly.d) if poly.a < poly.d else (poly.d, poly.a) # 3, 0
else : return (poly.c, poly.d) if poly.c < poly.d else (poly.d, poly.c) # 3, 2
return (-1, -1)
ListeAretesPolygone
http://code.vonc.fr/details/100/image_ListeAretesPolygone.png
def ListeAretesPolygone(poly) :
"""
Liste les arêtes d'un polygone.
Paramètres :
poly (CPolygon) - Polygone
Renvoie :
(tuple de tuple(int, int)) - Liste des arêtes, une arête étant un tuple trié de deux ID de points
"""
if poly.IsTriangle() :
return (
(poly.a, poly.b) if (poly.a < poly.b) else (poly.b, poly.a),
(poly.b, poly.c) if (poly.b < poly.c) else (poly.c, poly.b),
(poly.c, poly.a) if (poly.c < poly.a) else (poly.a, poly.c)
)
return (
(poly.a, poly.b) if (poly.a < poly.b) else (poly.b, poly.a),
(poly.b, poly.c) if (poly.b < poly.c) else (poly.c, poly.b),
(poly.c, poly.d) if (poly.c < poly.d) else (poly.d, poly.c),
(poly.d, poly.a) if (poly.d < poly.a) else (poly.a, poly.d)
)
ListeAretesPolygoneSensABCD
http://code.vonc.fr/details/100/image_ListeAretesPolygoneSensABCD.png
def ListeAretesPolygoneSensABCD(poly) :
"""
Liste les arêtes d'un polygone, les arêtes ici n'ont pas leurs indices triés.
Paramètres :
poly (CPolygon) - Polygone
Renvoie :
(tuple de tuple(int, int)) - Liste des arêtes, une arête étant ici un tuple non trié de deux ID de points
"""
if poly.IsTriangle() :
return (
(poly.a, poly.b),
(poly.b, poly.c),
(poly.c, poly.a)
)
return (
(poly.a, poly.b),
(poly.b, poly.c),
(poly.c, poly.d),
(poly.d, poly.a)
)
César Vonc
08/10/2017, 12h34
Opérations sur les matrices
TransposeMatrice
def TransposeMatrice(m) :
"""
Transpose une matrice.
Paramètres :
m (Matrix) - Matrice
"""
v1 = c4d.Vector(m.v1.x, m.v2.x, m.v3.x)
v2 = c4d.Vector(m.v1.y, m.v2.y, m.v3.y)
v3 = c4d.Vector(m.v1.z, m.v2.z, m.v3.z)
m.v1 = v1
m.v2 = v2
m.v3 = v3
m.off = c4d.Vector()
César Vonc
08/10/2017, 12h34
Opérations sur les vecteurs
RefleteVecteur
http://code.vonc.fr/details/100/image_RefleteVecteur.png
def RefleteVecteur(v, n) :
"""
Reflète un vecteur par rapport à une normale. La normale doit être normalisée.
Paramètres :
v (Vector) - Vecteur initial
n (Vector) - Vecteur normale (normalisée)
Renvoie :
(Vector) - Vecteur réfléchi
"""
return (2. * (v.Dot(n)) * n) - v
IntersectionSegments2DBool
http://code.vonc.fr/details/100/image_IntersectionSegments2DBool.png
def IntersectionSegments2DBool(p, p2, q, q2) :
"""
Détermine si deux segments 2D se croisent.
Paramètres :
p (Vector) - Point de départ du premier segment
p2 (Vector) - Point d'arrivée du premier segment
q (Vector) - Point de départ du second segment
q2 (Vector) - Point d'arrivée du second segment
Renvoie :
(bool) - Booléen
"""
def ccw(p, p2, q) :
return (q.y - p.y) * (p2.x - p.x) > (p2.y - p.y) * (q.x - p.x)
return ccw(p, q, q2) != ccw(p2, q, q2) and ccw(p, p2, q) != ccw(p, p2, q2)
IntersectionSegments2DVector
http://code.vonc.fr/details/100/image_IntersectionSegments2DVector.png
def IntersectionSegments2DVector(p, p2, q, q2) :
"""
Calcule le point d'intersection entre deux segments 2D.
Paramètres :
p (Vector) - Point de départ du premier segment
p2 (Vector) - Point d'arrivée du premier segment
q (Vector) - Point de départ du second segment
q2 (Vector) - Point d'arrivée du second segment
Renvoie :
(Vector ou None) - Point d'intersection
"""
def CrossScal(a, v) :
return a.x * v.y - a.y * v.x
r = p2 - p
s = q2 - q
rxs = CrossScal(r, s)
qpxr = CrossScal((q - p), r)
if rxs == 0. and qpxr == 0. :
return None
t = CrossScal((q - p), s) / rxs
u = qpxr / rxs
if (0 <= t and t <= 1) and (0 <= u and u <= 1) :
return p + t*r
return None
IntersectionDroites2DBool
http://code.vonc.fr/details/100/image_IntersectionDroites2DBool.png
def IntersectionDroites2DBool(p1, p2, q1, q2) :
"""
Détermine si deux droites 2D se croisent.
Paramètres :
p1 (Vector) - Point sur la première droite
p2 (Vector) - Point sur la première droite
q1 (Vector) - Point sur la seconde droite
q2 (Vector) - Point sur la seconde droite
Renvoie :
(bool) - Booléen
"""
pa = p1.y - p2.y
pb = p2.x - p1.x
qa = q1.y - q2.y
qb = q2.x - q1.x
d = pa * qb - pb * qa
return d != 0.
IntersectionDroites2DVector
http://code.vonc.fr/details/100/image_IntersectionDroites2DVector.png
def IntersectionDroites2DVector(p1, p2, q1, q2) :
"""
Calcule le point d'intersection entre deux droites 2D.
Paramètres :
p1 (Vector) - Point sur la première droite
p2 (Vector) - Point sur la première droite
q1 (Vector) - Point sur la seconde droite
q2 (Vector) - Point sur la seconde droite
Renvoie :
(Vector ou None) - Point d'intersection
"""
pa = p1.y - p2.y
pb = p2.x - p1.x
pc = p2.x * p1.y - p1.x * p2.y
qa = q1.y - q2.y
qb = q2.x - q1.x
qc = q2.x * q1.y - q1.x * q2.y
d = pa * qb - pb * qa
dx = pc * qb - pb * qc
dy = pa * qc - pc * qa
if d != 0. :
return c4d.Vector(dx / d, dy / d, 0.)
else :
return None
César Vonc
08/10/2017, 12h36
Sélections
BaseSelectAretesToutes
def BaseSelectAretesToutes(obj) :
"""
Renvoie le BaseSelect de toutes les arêtes sélectionnées.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(BaseSelect) - Sélection de toutes les arêtes sélectionnées
"""
bs = c4d.BaseSelect()
nbPolys = obj.GetPolygonCount()
bs.SelectAll(nbPolys * 4 - 1)
return bs
BaseSelectPolysDepuisAretes
http://code.vonc.fr/details/100/image_BaseSelectPolysDepuisAretes.png
def BaseSelectPolysDepuisAretes(obj, bsAretes) :
"""
Renvoie le BaseSelect des polys ayant au moins une arête sélectionnée.
Paramètres :
obj (PolygonObject) - Objet
bsAretes (BaseSelect) - Sélection d'arêtes
Renvoie :
(BaseSelect) - Sélection de polygones
"""
bs = c4d.BaseSelect()
nbAretes = obj.GetPolygonCount() * 4
for i, sel in enumerate(bsAretes.GetAll(nbAretes)) :
if sel :
bs.Select(int(i / 4))
return bs
BaseSelectPolysTous
def BaseSelectPolysTous(obj) :
"""
Renvoie le BaseSelect de tous les polygones sélectionnés.
Paramètres :
obj (PolygonObject) - Objet
Renvoie :
(BaseSelect) - Sélection de polygones
"""
bs = c4d.BaseSelect()
nbPolys = obj.GetPolygonCount()
bs.SelectAll(nbPolys - 1)
return bs
SelectionnePointsTous
def SelectionnePointsTous(obj) :
"""
Sélectionne tous les points.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opoint) :
bs = obj.GetPointS()
bs.SelectAll(obj.GetPointCount() - 1)
SelectionnePointsPolysPoints
http://code.vonc.fr/details/100/image_SelectionnePointsPolysPoints.png
def SelectionnePointsPolysPoints(obj, nei = None) :
"""
Sélectionne tous les points des polys des points sélectionnés.
Paramètres :
obj (PolygonObject) - Objet
nei (Neighbor) - Neighbor initialisé
"""
if not obj.CheckType(c4d.Opolygon) : return
if not nei :
nei = c4d.utils.Neighbor()
nei.Init(obj)
nbPts = obj.GetPointCount()
polys = obj.GetAllPolygons()
bs = obj.GetPointS()
bs2 = c4d.BaseSelect()
bsTous = bs.GetAll(nbPts)
for i, sel in enumerate(bsTous) :
if not sel : continue
vois = nei.GetPointPolys(i)
for voi in vois :
pol = polys[voi]
bs2.Select(pol.a)
bs2.Select(pol.b)
bs2.Select(pol.c)
if pol.c != pol.d : bs2.Select(pol.d)
bs.Merge(bs2)
SelectionnePolysTous
def SelectionnePolysTous(obj) :
"""
Sélectionne tous les polygones.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPolygonS()
bs.SelectAll(obj.GetPolygonCount() - 1)
SelectionnePolysInverse
def SelectionnePolysInverse(obj) :
"""
Inverse la sélection de polys courante.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPolygonS()
bs.ToggleAll(0, obj.GetPolygonCount() - 1)
SelectionnePolysAucun
def SelectionnePolysAucun(obj) :
"""
Désélectionne tous les polygones.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPolygonS()
bs.DeselectAll()
SelectionneAretesToutes
def SelectionneAretesToutes(obj, doc) :
"""
Sélectionne toutes les arêtes.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
"""
c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_SELECTALL,
list = [obj],
mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
doc = doc)
SelectionneAretesInverse
def SelectionneAretesInverse(obj, doc) :
"""
Inverse la sélection d'arêtes courante.
Paramètres :
obj (PolygonObject) - Objet
doc (BaseDocument) - Document
"""
c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_SELECTINVERSE,
list = [obj],
mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
doc = doc)
SelectionneAretesAucune
def SelectionneAretesAucune(obj) :
"""
Désélectionne toutes les arêtes.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetEdgeS()
bs.DeselectAll()
SelectionneAretesContour
http://code.vonc.fr/details/100/image_SelectionneAretesContour.png
def SelectionneAretesContour(obj, n = None) :
"""
Sélectionne les arêtes de contour.
Paramètres :
obj (PolygonObject) - Objet
n (Neighbor) - Neighbor initialisé
"""
if not obj : return
if obj.GetType() != c4d.Opolygon: return
nbPolys = obj.GetPolygonCount()
polys = obj.GetAllPolygons()
bs = c4d.BaseSelect()
bsAre = obj.GetEdgeS().GetClone()
if n is None :
n = c4d.utils.Neighbor()
n.Init(obj)
for i, pol in enumerate(polys):
pa = pol.a
pb = pol.b
pc = pol.c
pd = pol.d
nab = n.GetNeighbor(pa, pb, i)
nbc = n.GetNeighbor(pb, pc, i)
ncd = n.GetNeighbor(pc, pd, i)
nda = n.GetNeighbor(pd, pa, i)
cotes = n.GetPolyInfo(i)["edge"]
if nab == -1:
bs.Select(cotes[0])
if nbc == -1:
bs.Select(cotes[1])
if ncd == -1:
if pc != pd: bs.Select(cotes[2])
if nda == -1:
bs.Select(cotes[3])
obj.SetSelectedEdges(n, bs, c4d.EDGESELECTIONTYPE_SELECTION)
bs = obj.GetEdgeS()
bs.Merge(bsAre)
MarquagePointsDepuisAretes
http://code.vonc.fr/details/100/image_MarquagePointsDepuisAretes.png
def MarquagePointsDepuisAretes(obj, bsAretes = None, bsAretesGetAll = None) :
"""
Renvoie un tableau de marquage des points sélectionnés à partir d'une sélection d'arêtes.
Paramètres :
obj (PolygonObject) - Objet
bsAretes (BaseSelect) - Sélection d'arêtes
bsAretesGetAll (liste de int) - GetAll() du bsAretes
Renvoie :
(liste de bool) - Liste de booléens marquants les points sélectionnés des arêtes sélectionnées.
"""
polys = obj.GetAllPolygons()
nbPolys = obj.GetPolygonCount()
nbPts = obj.GetPointCount()
if bsAretes is None :
bsAretes = obj.GetEdgeS()
if bsAretesGetAll is None :
bsAretesGetAll = bsAretes.GetAll(nbPolys * 4)
ptsSel = [False] * nbPts
for i, pol in enumerate(polys) :
if not bsAretesGetAll[i*4] and not bsAretesGetAll[i*4+1] and not bsAretesGetAll[i*4+2] and not bsAretesGetAll[i*4+3] : continue
aretesPolySensABCD = VoncUtils.ListeAretesPolygoneSensABCD(pol)
for j, are in enumerate(aretesPolySensABCD) :
if bsAretesGetAll[i*4 + j] :
ptsSel[are[0]] = True
ptsSel[are[1]] = True
if pol.c == pol.d :
if bsAretesGetAll[i*4 + 3] :
are = aretesPolySensABCD[2]
ptsSel[are[0]] = True
ptsSel[are[1]] = True
return ptsSel
AffichePolysTous
def AffichePolysTous(obj) :
"""
Affiche tous les polygones.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPolygonH()
bs.DeselectAll()
AffichePointsTous
def AffichePointsTous(obj) :
"""
Affiche tous les polygones.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPointH()
bs.DeselectAll()
AfficheAretesToutes
def AfficheAretesToutes(obj) :
"""
Affiche toutes les arêtes.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetEdgeH()
bs.DeselectAll()
César Vonc
08/10/2017, 12h36
Débug
DebugVecteur
def DebugVecteur(doc, a, b = None, coul = c4d.Vector(1.), nom = "vec") :
"""
Ajoute un vecteur au document.
Paramètres :
doc (BaseDocument) - Document
a (Vector) - Position de début
b (Vector) - Position de fin
coul (Vector) - Couleur du vecteur
nom (string) - Nom du vecteur
"""
groupe = doc.SearchObject("debug")
if groupe is None :
groupe = c4d.BaseObject(c4d.Onull)
groupe.SetName("debug")
doc.InsertObject(groupe)
doc.AddUndo(c4d.UNDOTYPE_NEW, groupe)
p = None
if b is None :
p = c4d.BaseObject(c4d.Onull)
p[c4d.NULLOBJECT_DISPLAY] = 1
p[c4d.NULLOBJECT_RADIUS] = 3.
else :
p = c4d.BaseObject(c4d.Ospline)
p.ResizeObject(2)
p.SetAllPoints([c4d.Vector(), b - a])
p.Message(c4d.MSG_UPDATE)
p.SetName(nom)
p[c4d.ID_BASEOBJECT_USECOLOR] = 2
p[c4d.ID_BASEOBJECT_COLOR] = coul
p[c4d.ID_BASEOBJECT_REL_POSITION] = a
p.InsertUnder(groupe)
doc.AddUndo(c4d.UNDOTYPE_NEW, p)
DebugTexte
def DebugTexte(doc, pos = c4d.Vector(), texte = "texte", taille = 16., coul = c4d.Vector(1.)) :
"""
Ajoute un texte au document.
Paramètres :
doc (BaseDocument) - Document
pos (Vector) - Position
texte (string) - Texte à afficher
taille (float) - Taille de la police
couleur (Vector) - Couleur de la police
"""
groupe = doc.SearchObject("debug")
if groupe is None :
groupe = c4d.BaseObject(c4d.Onull)
groupe.SetName("debug")
doc.InsertObject(groupe)
doc.AddUndo(c4d.UNDOTYPE_NEW, groupe)
p = c4d.BaseObject(1019268)
p.MakeTag(1001001)
p[c4d.PRIM_TEXT_VSPACING] = - taille + (taille / 4.)
p[c4d.ID_BASEOBJECT_USECOLOR] = 2
p[c4d.ID_BASEOBJECT_COLOR] = coul
p[c4d.PRIM_TEXT_HEIGHT] = taille
p[c4d.ID_BASEOBJECT_REL_SCALE,c4d.VECTOR_X] = -1.
p[c4d.PRIM_TEXT_ALIGN] = 1
p[c4d.MGTEXTOBJECT_SPLINEMOVE] = 0.
p[c4d.PRIM_TEXT_TEXT] = "\n" + texte
p[c4d.ID_BASEOBJECT_REL_POSITION] = pos
p.InsertUnder(groupe)
doc.AddUndo(c4d.UNDOTYPE_NEW, p)
César Vonc
08/10/2017, 12h38
Réservé.
waouw merci César :) .
j'ai encore du mal avec Python mais tout ça me sera surement bien utile !
Ca donne envie de s'y mettre ! En tout les cas, c'est un travail extraordinaire. :ninja:
Superbe, quel boulot ! Merci beaucoup pour le partage, c'est vraiment super utile. Et hop, c'est déjà dans mon dossier site-packages .
César Vonc
09/10/2017, 22h09
Merci, lance-toi Aurety, tu verras, c'est addictif. :icon_mrgreen:
valkaari
17/10/2017, 08h20
Bravo pour le taf, tu devrais coller ça sur un github ou autre. On pourrais particichier
je l'ai pas vu je sais pas si tu l'as, j'en ai eu besoin pour une triangulation Delaunay on trouve la formule un peu partout.
def CercleCirconscrit(A,B,C):
"""
renvoie le centre du cercle circonscrit et son rayon
"""
a = A-C
b = B-C
n = b.Cross(a)
p0 = n.Cross( a.Dot(a) * b - b.Dot(b)*a) * (0.5 / n.Dot(n)) + C
r = 0.25 * a.Dot(a) * b.Dot(b) * (a-b).Dot(a-b) / n.Dot(n)
return p0, math.sqrt(r)
+1 pour le github ! En tout cas super documentations !
Voici quelques fonctions pour la gestions des VertexMaps dans c4d, qui n'est pas vraiment accessible en python.
https://gist.github.com/gr4ph0s/1bc0075ce733afb8b6678531a37f065b
Ou encore un simple script de LookAt entre deux objets
def LookAt(SrcObj, DestObj, RightNormalized=c4d.Vector(0,1,0)):
if not SrcObj or not DestObj:
return
#Get global pos
srcPos = SrcObj.GetMg().off
destPos = DestObj.GetMg().off
#Build front axis
forward = srcPos - destPos
forward.Normalize()
#Build right axis
right = RightNormalized.GetNormalized().Cross(forward)
#Build up axis
up = forward.Cross(right)
#Build the final matrice
m = SrcObj.GetMg()
m.v1 = right
m.v2 = up
m.v3 = forward
#Set new matrice
scale = SrcObj.GetRelScale()
SrcObj.SetMg(m)
SrcObj.SetRelScale(scale)
c4d.EventAdd()
impressionnant! :icon_eek: même si je ne comprends rien (c'est peut-être aussi pour ça que ça m'impressionne...)
César Vonc
28/10/2017, 00h51
Merci pour le code, je vais les implémenter ! :)
En effet, pas bête pour le dépôt git, je m'y mets ! :icon_mrgreen:
Est-ce que tu crois qu'il serait facile de faire un petit utilitaire de réattribution des IDs d'un mesh , pour que ça 'match' un autre mesh (dont le nbre de points est le même ) . Par ex des fois j'ai besoin d'importer des cibles de morphing pour un mesh ..et ces cibles sont extérieures (importées en obj par ex )..mais les IDs des points sont tous modifiés malgré le même nombre de points à la base . J'avais essayé / commencé un script en COFFEE pour choisir 3 points de départ sur mon mesh target et recalculer les IDs des points sur le mesh cibre pour que ça match et pouvoir ainsi importer ce mesh cible en target relative de morph dans un tag morph. J'ai pas poussé l'expérience Coffee bien plus loin la dessus mais peut-être qu'en python il y a des commandes plus simples pour faire ça ?
merki
César Vonc
28/10/2017, 20h13
Je vois ton souci, Clemz, et ça me semble loin d'être aussi simple que ça en a l'air.
On peut imaginer partir de deux ID de point définis sur les deux objets, de tourner autour de la même façon pour récupérer une liste de points ordonnés de la même manière, puis de réattribuer les points de l'un à l'autre.
Une des fonctions les plus utiles est, à mon avis, CalculePointPolysTries, qui renvoie la même chose que Neighbor.GetPointPolys, sauf que les polygones sont triés par sens horaire. Je pense qu'il y a moyen de s'en servir ou de le modifier pour récupérer les points triés autour d'un point donné.
Dans le principe, de manière récursive :
NouvelleListe = []
Sélectionner deux points A et B adjacents
ChercherPoints(A, B, NouvelleListe)
def ChercherPoints(A, B, NouvelleListe) :
Récupérer les points (triés par sens horaire) autour du point A, et dont le premier point de la liste est B
PointsAutour, PolysAutour = CalculePointsAutourTries(A, B) # à coder
Return si le premier PolyAutour est marqué
Ajouter dans NouvelleListe les points (en vert) qui ne sont pas marqués
Marquer les points ajoutés
Marquer les polygones autour
Pour chaque point dans PointsAutour :
Définir un point A, et le suivant de la liste comme étant B
# Break si le point A et B étaient marqués ?
ChercherPoints(A, B, Nouvelle Liste)
Reste plus qu'à gribouiller, si j'ai le temps je ferai ça, mais depuis mon nouveau boulot c'est compliqué d'avoir le temps !
20550
Je devrait avoir du temps demain, je testerais des trucs, mais j'ouvrirais un autre poste histoire de pas polluer celui-ci.
Si ça te dérange pas que j'utilise ton algo bien sur ;)
César Vonc
28/10/2017, 22h21
Non t'inquiète, c'est fait pour être partagé ! :biggrin:
yes merci les gars :) . Oui c'était ce genre de routine que je pensais essayer de faire . Fût un temps j'utilisais le plugin 'MorphMill ' qui lui avait un outil comme ça de retarget d'IDs . mais je crois qu'il n'a jamais été mis a jour pour suivre les nouvelles versions .
J'ai réussi une première implémentation récursive de ton algo modifié( je n'utilise qu'un seul point et non deux).
Sur de gros mesh, on atteins vite la limite de récursion et oui je peux l'augmenter, mais je préfère essayer de me casser la tête pour éviter cette récursion et modifier l'algorithme. Mais pour le moment ça fonctionne pas trop mal. Après ça ne supporte pas que les meshs weld ensemble et je n'ai pas testé avec des ngons, donc reste pas mal de bouleau.
J'ai aussi pensé à un autre algo plus simple qui s’appuierait sur des UV identique, ça fonctionne bien pour le moment, mais contraignant, vu qu'il faut que les deux mesh aient les même uv (En gros j'écrit dans une image, l'id d'un point sous forme d'une couleur et par la suite je lit cette couleur et interprète l'id)
EDIT: Bon j'ai réussi à faire un algo par itération plutôt que par récursion, mais le code est dégueu.
import c4d
import array
def set_pt_weight(vertex_map, pt_id, pt_weight):
# vertex_map => c4d.Tvertexmap
# pt_id => int
# pt_weight => float
if not vertex_map: return None
# if it's a baseObject we create a vertex_map
if isinstance(op, c4d.BaseObject):
buffer = vertex_map.GetTag(c4d.Tvertexmap)
if not buffer:
vertex_map = c4d.VariableTag(c4d.Tvertexmap, op.GetPointCount())
op.InsertTag(vertex_map)
else:
vertex_map = buffer
else:
vertex_tag = op
# Check the pt_id filled is correct
if pt_id > vertex_map.GetDataCount() or pt_id < 0: return None
# Get the write buffer array
buffer = vertex_map.GetLowlevelDataAddressW()
if buffer is None: return None
# Translate float into Bytseq float
floatArray = array.array('f')
floatArray.append(pt_weight)
data = floatArray.tostring()
# float get a size of 4. Since pt_id are ordered we just have to make pt_id*4 to get the start of the array
buffer[pt_id*4: pt_id*4+4] = data
return True
def GetOrderPoint(poly, basePtID):
returnPtOrdered = list()
listPtID = list()
indexInPoly = None
count = int( not poly.IsTriangle())
listId = range(0,3 + count)
for i in listId:
if i == 0:
bufferPoly = poly.a
elif i == 1:
bufferPoly = poly.b
elif i == 2:
bufferPoly = poly.c
elif i == 3:
bufferPoly = poly.d
if bufferPoly == basePtID:
indexInPoly = i
if indexInPoly is None: return
listPtID += listId[indexInPoly:]
listPtID += listId[:indexInPoly]
for i in listPtID:
if i == 0:
bufferPoly = poly.a
elif i == 1:
bufferPoly = poly.b
elif i == 2:
bufferPoly = poly.c
elif i == 3:
bufferPoly = poly.d
returnPtOrdered.append(bufferPoly)
return returnPtOrdered
def iterateAl(obj, ptID, listMarkPt=None, listMarkPoly=None, count=None):
if listMarkPt is None:
listMarkPt = list()
if listMarkPoly is None:
listMarkPoly = list()
if count is None:
count = [0]
# mark ptID
set_pt_weight(obj, ptID, 1.0)
listMarkPt.append(ptID)
count[0] += 1
print "{} - {}/{}".format(ptID, count[0], obj.GetPointCount())
#Get all no marked polys around ptID
nbr = c4d.utils.Neighbor()
nbr.Init(obj)
NbrPolysID = nbr.GetPointPolys(ptID)
listPolyToDo = list()
for polyID in NbrPolysID:
poly = obj.GetPolygon(polyID)
if polyID not in listMarkPoly:
listPolyToDo.append(polyID)
# Get all points over all no marked polys and repeat
listPtToDo = list()
for poly in listPolyToDo:
if poly in listMarkPoly:
continue
bufferPtToDO = GetOrderPoint(obj.GetPolygon(poly), ptID)
for ptIdBuffer in bufferPtToDO:
if not ptIdBuffer in listMarkPt and not ptIdBuffer == ptID and ptIdBuffer not in listPtToDo:
listPtToDo.append(ptIdBuffer)
listMarkPoly.append(poly)
return listPtToDo, listMarkPt, listMarkPoly, count
def main():
obj = doc.GetActiveObject()
listPtToDo = None
listMarkPt = None
listMarkPoly = None
count = None
objPtsCount = obj.GetPointCount()
lastPt = None
while 1:
#first loop
if count is None:
listPtToDo, listMarkPt, listMarkPoly, count = iterateAl(obj, 0)
#next loop
else:
for pt in listPtToDo:
if not pt in listMarkPt and not pt == lastPt:
bufferlistPtToDo, listMarkPt, listMarkPoly, count = iterateAl(obj, pt, listMarkPt, listMarkPoly, count)
listPtToDo += bufferlistPtToDo
lastPt = pt
if count[0] == objPtsCount:
break
if count[0] == objPtsCount:
break
c4d.EventAdd()
if __name__=='__main__':
main()
Comme vous pouvez le voir heureusement que les listes sont mutable(une référence), bon en tout cas c'est en bonne route :D
Juste pour info ces bouts de code sont sous quelle licence? Perso les miens sont sous MIT (d'ailleurs faudrait que je change sur mon github).
dites les codeurs fous , je me demandais si l'un d'entre vous ne voudrait pas nous pondre et vendre un petit script/plugin de manipulation de clés ? ( j'ai pas trop regardé si je pouvais le faire en COFFEE ) . ? je m'expliquasse :
de temps en temps on a besoin d'accélérer une zone dans une anim , ou de la ralentir ( par ex ça peut être un cycle de marche en boucle et je veux que ça s'accélère ou que ça ralentisse .. ) La seule solution que l'on peut faire c'est de sélectionner les clés dans le dopsheet et scaler ça en +ou- ( avec ou sans snapping auto aussi pour ne pas casser les espacements .. mais ça fait un scale uniforme ! ..donc pour faire une espèce de progression en "ease" il faut venir faire des sous séléctions de de scaler chacune un peu plus ou un peu moins et rabouter tout ça .. le bordel et ça reste crassou .
Donc mon idée était de me faire un petit script qui , d'une sélection de clés dans le dosheet me les compresseraient ou les allongeraient , mais avec un effet progressif/"exponentiel" ( ou inversement ) , mais surtout pas linéaire ..
(j'imaginais un petit popup modal qui proposerait 2 sliders '-100%+100%' : une qui ferait compression dans le négatif (-100%-0%) et allongement dans le positif (0%-100%) , et l'autre slider controlerait le type de répartition/espacement entre les clés ( = commande 'Bias' en code ) c'est à dire à 0% on aurait un espacement constant (comme C4D le fait actuellement ) et en -100% cela signifierait que plus les clés sont à gauche plus elles sont resserrées entre elles et espacées à droite ..et inversement en +100% : on compresse vers la droite .
On peut aussi avoir en option ( petit booléens à cocher ) : activer/désactiver le snap auto des clés .. recalculer le timing de la sélection de clés pour que si on strech ou compresse via le 'Bias' , le 1er espacement de clés reste non 'touché' niveau durée .
Comme j'ai bien compris que c'était peine perdue de demander ça aux dev de chez Maxon , la seule solution pour voir ce genre d'outil (indispensable pour un animateur à mon goût ) c'est de faire ça entre nous .
Ou peut -être auriez vous des petits bouts de codes concernant la manip de keyframes svp que je regarde ça de mon coté ?
merci
valkaari
21/11/2017, 20h24
gngngn
je peux regarder ça j'suis justement en train de faire un truc sur les clefs d'animation. J'en profite pour travailler sur des fonctions autres pour apprendre un peu plus le SDK donc ça prends du temps.
Une vrai mine d'or tout ça! Merci César et merci aux contributeurs je m'abonne :icon_clap:
César Vonc
28/01/2018, 22h10
Le dépot git a été créé pour ceux qui veulent participer. :)
https://bitbucket.org/codevonc/voncutils
Quelques nouveautés :
PointEstDansTriangle2D
def PointEstDansTriangle2D(pt, v1, v2, v3) :
"""
Détermine si un point se trouve dans un triangle 2D.
Paramètres :
pt (Vector) - Point à déterminer
v1 (Vector) - Point du triangle
v2 (Vector) - Point du triangle
v3 (Vector) - Point du triangle
Renvoie :
(bool) - Booléen, si le point est contenu dans le triangle ou non
"""
def signe(p1, p2, p3) :
return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)
b1 = signe(pt, v1, v2) < 0.0
b2 = signe(pt, v2, v3) < 0.0
b3 = signe(pt, v3, v1) < 0.0
return ((b1 == b2) and (b2 == b3))
SubdiviseLissePoints
def SubdiviseLissePoints(pts, nbPts, ferme) :
"""
Subdivise et lisse une liste de points qui se suivent.
Paramètres :
pts (liste de Vector) - Liste des points à subdiviser
nbPts (int) - Nombre de points de la liste
ferme (bool) - Définit si la liste de points forme une boucle
Renvoie :
(liste de Vector) - Nouvelle liste de points subdivisés et lissés
(int) - Nombre de points de la nouvelle liste
"""
nbPtsNouv = nbPts * 2
if not ferme : nbPtsNouv -= 1
ptsNouv = [c4d.Vector()] * nbPtsNouv
if nbPts == 0 :
return [], 0
if nbPts == 1 :
return [pts[0]], 1
j = 0
prec = c4d.Vector()
suiv = c4d.Vector()
pos = c4d.Vector()
nouv = c4d.Vector()
mil = c4d.Vector()
milPrec = c4d.Vector()
nbPtsMU = nbPts - 1
# i = 0
pos = pts[0]
suiv = pts[1]
mil = (pos + suiv) * 0.5
ptsNouv[j] = pos + 0.0 ; j += 1
ptsNouv[j] = mil ; j += 1
milPrec = mil
# 1 à nbPts-2
for i in xrange(1, nbPtsMU) :
pos = pts[i]
suiv = pts[i + 1]
mil = (pos + suiv) * 0.5
nouv = ((mil + milPrec) * 0.5 + pos) * 0.5
ptsNouv[j] = nouv ; j += 1
ptsNouv[j] = mil ; j += 1
prec = pos
milPrec = mil
# i = nbPts-1
pos = pts[nbPtsMU]
if not ferme :
ptsNouv[j] = pos + 0.0 ; j += 1
else :
suiv = pts[0]
mil = (pos + suiv) * 0.5
nouv = ((mil + milPrec) * 0.5 + pos) * 0.5
ptsNouv[j] = nouv ; j += 1
ptsNouv[j] = mil ; j += 1
milPrec = mil
mil = ptsNouv[1]
nouv = ((mil + milPrec) * 0.5 + pts[0]) * 0.5
ptsNouv[0] = nouv
return ptsNouv, nbPtsNouv
ProjetteVecteur
https://code.vonc.fr/details/100/image_ProjetteVecteur.png
def ProjetteVecteur(a, bNor) :
"""
Projette un vecteur A sur un vecteur B. Le vecteur B doit être normalisée.
Paramètres :
a (Vector) - Vecteur initial
b (Vector) - Vecteur de projection (normalisé)
Renvoie :
(Vector) - Vecteur projeté C
"""
return a.Dot(bNor) * bNor
RejetteVecteur
https://code.vonc.fr/details/100/image_RejetteVecteur.png
def RejetteVecteur(a, bNor) :
"""
Calcule la réjection d'un vecteur A sur un vecteur B. Le vecteur B doit être normalisée.
Paramètres :
a (Vector) - Vecteur initial
b (Vector) - Vecteur de réjection (normalisée)
Renvoie :
(Vector) - Vecteur rejeté C
"""
return a - a.Dot(bNor) * bNor
TransformeVecteur
https://code.vonc.fr/details/100/image_TransformeVecteur.png
def TransformeVecteur(a, b, c, transformeTaille = True) :
"""
Calcule la différence entre deux vecteurs et applique cette même déformation à un troisième vecteur.
Paramètres :
a (Vector) - Vecteur initial
b (Vector) - Vecteur initial transformé
c (Vector) - Vecteur à transformer
transformeTaille (Bool) - Si vrai, transforme également la taille du vecteur
Renvoie :
(Vector) - Vecteur transformé D
"""
aLon = a.GetLength()
if aLon == 0.0 :
return c4d.Vector()
bLon = b.GetLength()
if bLon == 0.0 :
return c4d.Vector()
cLon = c.GetLength()
if cLon == 0.0 :
return c4d.Vector()
facLon = bLon / aLon
b2 = b.GetNormalized() * cLon
n = (b2 + c) * 0.5
n.Normalize()
d = c4d.Vector()
# Cas où la normale est nulle
if n == c4d.Vector() :
d = -b
else :
d = (2. * (a.Dot(n)) * n) - a
d.Normalize()
if transformeTaille :
d *= cLon * facLon
return d
InterpoleDansTab
def InterpoleDansTab(nb, c) :
"""
Soit un tableau de longueur NB et C un curseur sur le tableau.
Cette fonction renvoie l'indices des cases autour du curseur et le facteur de mélange entre les deux cases.
Paramètres :
nb (int) - Taille du tableau
c (float) - Curseur, entre 0.0 et 1.0
Renvoie :
(int) - Case à gauche du curseur
(int) - Case à droite du curseur
(float) - Facteur de mélange entre les deux cases, entre 0.0 et 1.0
"""
a = 0
b = 0
f = 0.0
nbMU = nb - 1
if c > 0 :
bf = c * nbMU
b = int(math.ceil(bf))
a = b - 1
f = 1.0 - (b - bf)
if a >= nb : a = nbMU
if b >= nb : b = nbMU
if a < 0 : a = 0
if b < 0 : b = 0
return a, b, f
InterpoleLineaire
def InterpoleLineaire(pts, nb, t) :
"""
Interpole de façon linéaire une valeur dans un tableau de données
Paramètres :
pts (liste de Vector ou de float) - Liste des points de contrôles
t (float) - Facteur d'interpolation, entre 0.0 et 1.0
Renvoie :
(Vector ou float) - La valeur interpolée dans le tableau
"""
a, b, f = Utils.InterpoleDansTab(nb, t)
return (1.0 - f) * pts[a] + f * pts
InterpoleDoux
def[B] InterpoleDoux(pts, nb, t) :
"""
Interpole de façon adoucie une valeur dans un tableau de données
Paramètres :
pts (liste de Vector ou de float) - Liste des points de contrôles
t (float) - Facteur d'interpolation, entre 0.0 et 1.0
Renvoie :
(Vector ou float) - La valeur interpolée dans le tableau
"""
a, b, f = Utils.InterpoleDansTab(nb, t)
f = c4d.utils.Smoothstep(0.0, 1.0, f)
return (1.0 - f) * pts[a] + f * pts[b]
Vraiment super cool tout ces "snippets"
Pour le Git ca se passe comment ?
J'ai vu les bases pour utiliser Git. Faut dire que le tutorial de bitbucket est super bien fait. Pour l'aspect manips ça devrait aller. Par contre pour les "us et coutumes" là, j'ai aucune idée de comment ça se passe.
Admettons que je veuille rajouter des fichiers, je crée un nouveau repository (depot) sur ton compte ?
Si oui il faut le faire au niveau de c4d ?
Je me suis créé un compte bitbucket histoire de tester un peu. Il faut quand même un mot de passe pour acceder. Est ce que celui de mon compte suffit ?
Bon je demande ça car je pourrai éventuellement, si ca intéresse, créer une section plus basique genre orienté débutants ou scripteurs occasionnels. Comme moi quoi :icon_mrgreen:. Un genre de mémo pour les opérations de base.
Et au fait c'est bien le même dépot communautaire pour les projets open source dont tu parlais dans la discussion "deformateurs UV" ou c'est deux "projets" différents ?
César Vonc
29/01/2018, 21h36
Aah c'est chouette de te voir te lancer dedans !
Tu peux me filer ton identifiant bitbucket ? J'ai créé un groupe FC4D et tu pourras créer ton dépôt dedans. ;)
J'ai mis le dépôt sur https://bitbucket.org/fc4d/voncutils du coup. Ce sera celui à retenir pour ce projet.
On va mettre les projets communautaires dans cette équipe :
https://bitbucket.org/fc4d/
Une fois que t'as installé Git, tu vas dans le dossier de là où tu veux récupérer le projet et tu fais clic droit > Git bash here.
Ensuite :
git remote add origin https://CesarVonc@bitbucket.org/fc4d/voncutils.git
git pull origin master
La première ligne ajoute l'adresse du dépôt, la seconde télécharge les données.
Il va sûrement te demander une fois ton mot de passe Bit bucket.
Pour créer un dépôt, créés le d'abord sur https://bitbucket.org/fc4d/ puis :
Dans le dossier de ton projet : Clic droit > Git bash here
git init
git remote add origin [adresse du dépôt (repository) que te donne bitbucket quand tu en créés un]
git add -A (pour ajouter tous tes fichiers à envoyer, ou git add [nomdufichier] pour être plus spécifique)
git commit -m "Initialisation du projet blabla"
git push origin master (balance les fichiers dans ton dépôt)
Pour mettre à jour un dépôt, Clic droit > Git bash here :
git status (pas obligé, à faire quand tu veux pour voir les fichiers modifiés, ajoutés, "stagés" ou non)
git add -A (pour ajouter tous tes fichiers à envoyer, ou git add [nomdufichier] pour être plus spécifique)
git commit -m "Court message expliquant tes modifs"
git pull origin master (pour récupérer sur la branche master les éventuelles modifs faites par un tiers)
git push origin master (pour balancer tes modifs)
On verra après les branches, les tags, pour l'instant y a pas besoin.
Avant de faire quoi que ce soit dans git, renseigne ton nom et ton adresse mail sinon il risque de t'envoyer balader au premier push que tu voudras faire :
git config --global user.email "ton_adresse@mail.fr"
git config --global user.name "Floc"
Si tu veux que git ignore certains fichiers, créés un fichier .gitignore et écris sur chaque ligne la règle de fichier à ignorer (genre *.txt pour ignorer tous les fichiers txt du répertoire racine du projet, mesvideos/toutenuesurlaplage.mp4 pour exclure un fichier en particulier)
Si ton windows t'interdit de créer un fichier sans nom : clic droit > git bash here :
touch .gitignore
Merci pour toutes ces infos
mon identifiant bitbucket est : Fred_lc
Et juste histoire d'etre sur que j'ai bien compris :
Le dépôt "memo pour scripteurs du dimanche" ca serait sur codevonc.
Et le dépôt "texture Bombing" par exemple ce serait sur FC4D (je dis bien par exemple parce que pour l'instant l'écriture de plug-in j'en chie un peu :icon_mrgreen:)
César Vonc
29/01/2018, 22h13
Non, tout va sur FC4D, même ton mémo pour scripteurs du dimanche. On corrigera tes scripts si y a besoin, c'est le but. ;)
Le dossier Code Vonc sera juste pour moi. Ou pour vous quand je créerai ma propre communauté, un jour peut-être. :icon_mrgreen:
Je t'ai ajouté à l'équipe FC4D. Tu peux normalement y créer ton dépôt, maintenant.
ok
Oui corriger mes scripts ce sera surement inévitable :P
bon je tente la création du depot.
[edit] je vais peut etre préparer un peu de contenu avant :whistling:
César Vonc
04/02/2018, 16h14
Petite mise à jour avec l'ajout de l'interpolation par b-spline.
Imaginez un tableau de points pts, renseignez une valeur entre 0 et 1 pour récupérer la position du point sur la courbe déterminée par ce tableau.
Notez que ça peut être un tableau de points comme un tableau de couleurs, de flottants ou autre.
def InterpoleBezierQuadratique(pts, nb, t) :
"""
Interpole selon la courbe de Bézier Quadratique une valeur dans un tableau de données
Paramètres :
pts (liste de Vector ou de float) - Liste des points de contrôles
nb (int) - Taille du tableau
t (float) - Facteur d'interpolation, entre 0.0 et 1.0
Renvoie :
(Vector ou float) - La valeur interpolée dans le tableau
"""
if nb <= 2 :
return VoncUtils.InterpoleLineaire(pts, nb, t)
nbU = nb - 1
nbT = nb - 3
nbU2Inv = 1. / (nbU * 2)
tf = (t - nbU2Inv) * nbU
i0 = int(tf)
i1 = i0 + 1
i2 = i1 + 1
if nb == 3 : # 3 points
f = t
p0 = pts[0]
p1 = pts[1]
p2 = pts[2]
elif i0 == 0 : # Début
f = (tf + 0.5) / 1.5
p0 = pts[i0]
p1 = pts[i1]
p2 = (pts[i1] + pts[i2]) * .5
elif i0 >= nbT : # Fin
f = (tf - nbT) / 1.5
i0 = nbT
i1 = i0 + 1
i2 = i1 + 1
p0 = (pts[i0] + pts[i1]) * .5
p1 = pts[i1]
p2 = pts[i2]
else : # Milieu
f = tf - i0
p0 = (pts[i0] + pts[i1]) * .5
p1 = pts[i1]
p2 = (pts[i1] + pts[i2]) * .5
return VoncUtils.CourbeBezierQuadratique(p0, p1, p2, f)
def CourbeBezierQuadratique(p0, p1, p2, t) :
"""
Courbe de Bézier Quadratique
Paramètres :
p0 (Vector ou float) - Premier point
p1 (Vector ou float) - Deuxième point
p2 (Vector ou float) - Troisième point
t (float) - Facteur d'interpolation entre 0.0 et 1.0
Renvoie :
(Vector ou float) - Le point sur la courbe
"""
t1 = 1.0 - t
return t1 * t1 * p0 + 2.0 * t * t1 * p1 + t * t * p2
Powered by vBulletin® Version 4.2.1 Copyright © 2024 vBulletin Solutions, Inc. Tous droits réservés