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 !
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).
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
DebugVecteur
DebugTexte
Vous pouvez retrouver ou télécharger la classe ici : http://code.vonc.fr/?a=100
Dernière modification par César Vonc ; 08/10/2017 à 12h49.
Calculs sur un objet
CalculeNormalesPolys
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Dernière modification par César Vonc ; 08/10/2017 à 13h44.
Calculs géométriques
VolumeTetraedre
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Dernière modification par César Vonc ; 08/10/2017 à 13h38.
Modification d'un objet
BruiteObjet
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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)
Dernière modification par César Vonc ; 08/10/2017 à 13h45.
Opérations sur les polygones
AreteOpposee
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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)
)
Dernière modification par César Vonc ; 08/10/2017 à 13h40.
Opérations sur les matrices
TransposeMatrice
Code PHP:
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()
Dernière modification par César Vonc ; 08/10/2017 à 13h39.
Opérations sur les vecteurs
RefleteVecteur
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Dernière modification par César Vonc ; 28/01/2018 à 21h36.
Sélections
BaseSelectAretesToutes
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
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
Code PHP:
def AffichePolysTous(obj) :
"""
Affiche tous les polygones.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPolygonH()
bs.DeselectAll()
AffichePointsTous
Code PHP:
def AffichePointsTous(obj) :
"""
Affiche tous les polygones.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetPointH()
bs.DeselectAll()
AfficheAretesToutes
Code PHP:
def AfficheAretesToutes(obj) :
"""
Affiche toutes les arêtes.
Paramètres :
obj (PolygonObject) - Objet
"""
if obj.CheckType(c4d.Opolygon) :
bs = obj.GetEdgeH()
bs.DeselectAll()
Dernière modification par César Vonc ; 08/10/2017 à 13h42.
Débug
DebugVecteur
Code PHP:
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
Code PHP:
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)
Dernière modification par César Vonc ; 08/10/2017 à 12h39.
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.
kenavo !! // Pinterest KAMIGAZ®
Superbe, quel boulot ! Merci beaucoup pour le partage, c'est vraiment super utile. Et hop, c'est déjà dans mon dossier site-packages .
Merci, lance-toi Aurety, tu verras, c'est addictif.
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.
Code: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)
Dernière modification par valkaari ; 17/10/2017 à 08h33.
+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/1bc0...678531a37f065b
Ou encore un simple script de LookAt entre deux objets
Code: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()
Dernière modification par gr4ph0s ; 17/10/2017 à 11h00.
SDK Specialist
MAXON Computer GmbH
impressionnant! même si je ne comprends rien (c'est peut-être aussi pour ça que ça m'impressionne...)
La chance sourit aux audacieux : pourvu qu’elle n’ait pas de caries.
http://yoniverse.jimdo.com/
Merci pour le code, je vais les implémenter !
En effet, pas bête pour le dépôt git, je m'y mets !
Génial ! Merci césar.
Il n'y a pas d’échecs, seulement des leçons! Pour peut que nous les comprenions...
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
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 :
Code: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 !
Dernière modification par César Vonc ; 28/10/2017 à 20h26.
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
SDK Specialist
MAXON Computer GmbH
Non t'inquiète, c'est fait pour être partagé !
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.
Comme vous pouvez le voir heureusement que les listes sont mutable(une référence), bon en tout cas c'est en bonne routeCode: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()
Dernière modification par gr4ph0s ; 30/10/2017 à 18h51.
SDK Specialist
MAXON Computer GmbH
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).
SDK Specialist
MAXON Computer GmbH
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
.
merci Manu .
Une vrai mine d'or tout ça! Merci César et merci aux contributeurs je m'abonne