PDA

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é.

clemz
08/10/2017, 16h13
waouw merci César :) .

j'ai encore du mal avec Python mais tout ça me sera surement bien utile !

Aurety
08/10/2017, 17h51
Ca donne envie de s'y mettre ! En tout les cas, c'est un travail extraordinaire. :ninja:

oli_d
09/10/2017, 05h34
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)

gr4ph0s
17/10/2017, 10h51
+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()

leBigYO
19/10/2017, 22h01
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:

Neraw
28/10/2017, 16h37
Génial ! Merci césar.

clemz
28/10/2017, 16h50
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

gr4ph0s
28/10/2017, 20h34
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:

clemz
30/10/2017, 16h31
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 .

gr4ph0s
30/10/2017, 18h25
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

gr4ph0s
14/11/2017, 21h29
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).

clemz
19/11/2017, 16h55
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.

clemz
21/11/2017, 21h11
:D .
merci Manu ;) .

lakpo
11/12/2017, 15h57
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]

Floc
29/01/2018, 20h26
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

Floc
29/01/2018, 22h03
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.

Floc
29/01/2018, 22h29
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