Contenu mis en avant
Dépliage

Plugin Cinema 4D

Alvéole

Plugin Cinema 4D

Projecteur UV

Plugin Cinema 4D

Vonc Utils

 

DescriptionCalculs sur un objetCalcule Normales PolysCalcule Normales PointsCalcule Normales Points PolysCalcule Centre PolysCalcule Decentre Bruit PolysCalcule le Nombre d'Arêtes de chaque polygoneCalcule Aire PolysCalcule Aire Polys FacteurCalcule Perimetre PolysCalcule Orthocentre TrianglesCalcule Nb Polys Par PointCalcule Points Bordure ListeCalcule Points Bordure MarquageCalcule Points Bordure Select MarquageCalcule AretesDictionnaire AretesCalcule Aretes BordureCalcule Aretes Bordure Avec PolysCalcule Polys Bordure MarquageCalcule Point Polys TriesCalcule Liaison PointsCalcule Groupes Par PolyCalcule Groupes Par Poly PhongBruit PointsCalcule sur les SplinesSubdivise Lisse PointsCalculs géométriquesVolume TetraedreAire PolygonePerimetre PolygoneOrthocentre TriangleModification d'une splineIntersection SplinesModification d'un objetBruiteObjetLissage Catmull ClarkRecopie ObjetOptimiserAligner NormalesInverser NormalesTriangulerQuadrangulerSubdiviserFermer TrousBiseauter CommandeBiseauter C4DExtruder C4DExtruderReduction De PolysSupprimer PolygonesOpérations sur les polygonesArete OpposeeArete AdjacenteListe Aretes PolygoneListe Aretes Polygone Sens ABCDQuadrangle Est ConvexeCalcule un Cercle Dans un Triangle IsocèleOpérations sur les matricesTranspose MatriceOpérations sur les vecteursReflete VecteurProjette VecteurRejette VecteurTransforme VecteurIntersection Segments 2D BoolIntersection Segments 2D VectorIntersection Droites 2D BoolIntersection Droites 2D VectorPoint Est Dans Triangle 2DInterpolationsInterpole Dans TabInterpole LineaireInterpole DouxInterpole Bezier QuadratiqueCourbe Bezier QuadratiqueSélectionsBase Select Aretes ToutesBase Select Polys Depuis AretesBase Select Polys TousSelectionne Points TousSelectionne Points Polys PointsSelectionne Polys TousSelectionne Polys InverseSelectionne Aretes ToutesSelectionne Aretes InverseSelectionne Aretes AucuneSelectionne Aretes ContourMarquage Points Depuis AretesAffiche Polys TousAffiche Points TousAffiche Aretes ToutesDébugDebug VecteurDebug Texte
Description

Fonctions utilitaires applicables sur un modèle 3D

Calculs sur un objet
    @staticmethod
    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


Calcule Normales Polys

    @staticmethod
    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


Calcule Normales Points

    @staticmethod
    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


Calcule Normales Points Polys

    @staticmethod
    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


Calcule Centre Polys

    @staticmethod
    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


Calcule Decentre Bruit Polys

    @staticmethod
    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


Calcule le Nombre d'Arêtes de chaque polygone

    @staticmethod
    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


Calcule Aire Polys

    @staticmethod
    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


Calcule Aire Polys Facteur

    @staticmethod
    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


Calcule Perimetre Polys

    @staticmethod
    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


Calcule Orthocentre Triangles

    @staticmethod
    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


Calcule Nb Polys Par Point

    @staticmethod
    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


Calcule Points Bordure Liste

    @staticmethod
    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


Calcule Points Bordure Marquage

    @staticmethod
    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


Calcule Points Bordure Select Marquage

    @staticmethod
    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


Calcule Aretes

    @staticmethod
    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


Dictionnaire Aretes

    @staticmethod
    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


Calcule Aretes Bordure

    @staticmethod
    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


Calcule Aretes Bordure Avec Polys

    @staticmethod
    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


Calcule Polys Bordure Marquage

    @staticmethod
    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()

        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


Calcule Point Polys Tries

    @staticmethod
    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


Calcule Liaison Points

    @staticmethod
    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


Calcule Groupes Par Poly

    @staticmethod
    def CalculeGroupesParPolyPhong(obj, n = None, angle = None):

        """
            Calcule pour chaque poly l'ID du groupe de polygones auquel il appartient, en séparant par les arêtes non lissées

            Paramètres :
                obj (PolygonObject) - Objet
                n (Neighbor) - Neighbor initialisé de l'objet
                angle (float) - Angle limite, None pour utiliser le lissage Phong

            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

        if not n:
            n = c4d.utils.Neighbor()
            n.Init(obj)

        def GetPhongTag(o):
            if not o:
                return None
            tags = o.GetTags()
            for tag in tags:
                if tag.GetType() == c4d.Tphong:
                    return tag

        angleLimite = 0.0
        utiliserEdgeBreak = True

        if angle is not None:
            angleLimite = angle
        else:
            phongTag = GetPhongTag(obj)
            if phongTag:
                angleLimite = phongTag[c4d.PHONGTAG_PHONG_ANGLE] if phongTag[c4d.PHONGTAG_PHONG_ANGLELIMIT] else 3.141592653589793
                utiliserEdgeBreak = phongTag[c4d.PHONGTAG_PHONG_USEEDGES]

        aretesPhongBS = obj.GetShadingBreak(True, utiliserEdgeBreak, True, angleLimite, angleLimite)
        aretesPhong = aretesPhongBS.GetAll(nbPolys * 4)

        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]
                    p4 = p * 4

                    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 = n.GetNeighbor(poly.c, poly.d, p) if poly.c != poly.d else c4d.NOTOK

                    if voisA != c4d.NOTOK and polysGroupe[voisA] == -1 and not aretesPhong[p4]:
                        polysATraiterSuivant.append(voisA)

                    if voisB != c4d.NOTOK and polysGroupe[voisB] == -1 and not aretesPhong[p4 + 1]:
                        polysATraiterSuivant.append(voisB)

                    if voisC != c4d.NOTOK and polysGroupe[voisC] == -1 and not aretesPhong[p4 + 2]:
                        polysATraiterSuivant.append(voisC)

                    if voisD != c4d.NOTOK and polysGroupe[voisD] == -1 and not aretesPhong[p4 + 3]:
                        polysATraiterSuivant.append(voisD)

                polysATraiter = list(set(polysATraiterSuivant))

            nbGroupes += 1

        return polysGroupe, nbGroupes


Calcule Groupes Par Poly Phong

    @staticmethod
    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

        for i in xrange(nbPts) :

            bruit[i] = noise(pts[i] * echelle, temps) * intensite

        return bruit


Bruit Points

Calcule sur les Splines
    @staticmethod
    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
        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

            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


Subdivise Lisse Points
Calculs géométriques
    @staticmethod
    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


Volume Tetraedre
    @staticmethod
    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


Aire Polygone
    @staticmethod
    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()


Perimetre Polygone
    @staticmethod
    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


Orthocentre Triangle
Modification d'une spline
    @staticmethod
    def IntersectionSplines(objs, precision=0.001, axe='y'):

        """
            Ajoute des points d'intersections à des splines 2D.

            Paramètres :
                objs (liste de SplineObject) - Liste des splines à modifier
                precision (float) - Précision (ou arrondi) du calcul des intersections
                axe (string) - Axe de profondeur (x, y, ou z)
        """

        aretes = []
        aretesAModifier = []
        points = []
        mgis = []

        # Aretes

        for s, spline in enumerate(objs):

            mg = spline.GetMg()
            mgis.append(~mg)
            nbPoints = spline.GetPointCount()
            pts = [mg * x for x in spline.GetAllPoints()]
            points.append(pts)

            segments = spline.GetSegmentCount()
            getSegment = spline.GetSegment
            if 0 == segments:
                segments = 1
                getSegment = lambda i: {'closed': spline[c4d.SPLINEOBJECT_CLOSED] and nbPoints > 2, 'cnt': nbPoints}

            j = 0
            for i in range(segments):
                segment = getSegment(i)
                cnt = segment['cnt']
                closed = (segment['closed'] or spline[c4d.SPLINEOBJECT_CLOSED]) and cnt > 2

                if cnt == 1:
                    j += 1
                    continue

                for k in range(cnt):
                    if k == 0:
                        continue

                    b = k + j
                    a = b - 1
                    aretes.append((s, a, b, i, False, k == cnt - 1))
                    aretesAModifier.append([])

                if closed:
                    a = j
                    b = j + cnt - 1
                    aretes.append((s, a, b, i, True, False))
                    aretesAModifier.append([])

                j += cnt

        # Intersections

        def estLoinDe(x, pa, pb, qa, qb, arr):
            return ((x - pa).GetLengthSquared() > arr and
                    (x - pb).GetLengthSquared() > arr and
                    (x - qa).GetLengthSquared() > arr and
                    (x - qb).GetLengthSquared() > arr)

        def estLoinDe2(x, pa, pb, arr):
            return ((x - pa).GetLengthSquared() > arr and
                    (x - pb).GetLengthSquared() > arr)

        def point3dVers2d(v):
            if axe == 'y':
                return c4d.Vector(v.x, v.z, 0.0)
            elif axe == 'x':
                return c4d.Vector(v.y, v.z, 0.0)
            return c4d.Vector(v.x, v.y, 0.0)

        def point2dVers3d(v):
            if axe == 'y':
                return c4d.Vector(v.x, 0.0, v.y)
            elif axe == 'x':
                return c4d.Vector(0.0, v.x, v.y)
            return c4d.Vector(v.x, v.y, 0.0)

        imax = len(aretes)
        arrondi = precision
        arrondi2 = precision * precision
        PointLineSegmentDistance2D = c4d.utils.PointLineSegmentDistance2D

        for i in range(imax):

            arete = aretes[i]
            spline = objs[arete[0]]
            mgi = mgis[arete[0]]
            pts = points[arete[0]]
            pa = pts[arete[1]]
            pb = pts[arete[2]]

            for j in range(i + 1, imax):

                arete2 = aretes[j]
                spline2 = objs[arete2[0]]
                mgi2 = mgis[arete2[0]]
                pts2 = points[arete2[0]]
                qa = pts2[arete2[1]]
                qb = pts2[arete2[2]]

                if pa == qa or pa == qb or pb == qa or pb == qb:
                    continue

                if not estLoinDe2(pa, qa, qb, arrondi2) or not estLoinDe2(pb, qa, qb, arrondi2):
                    continue
                if not estLoinDe2(qa, pa, pb, arrondi2) or not estLoinDe2(qb, pa, pb, arrondi2):
                    continue

                pa2d = point3dVers2d(pa)
                pb2d = point3dVers2d(pb)
                qa2d = point3dVers2d(qa)
                qb2d = point3dVers2d(qb)

                intersection = IntersectionSegments2DVector(pa2d, pb2d, qa2d, qb2d)

                if intersection is not None:
                    if arrondi < 0.001 or estLoinDe(intersection, pa, pb, qa, qb, arrondi2):
                        intersection = point2dVers3d(intersection)
                        aretesAModifier[i].append(mgi * intersection)
                        aretesAModifier[j].append(mgi2 * intersection)

                if arrondi < 0.001:
                    continue

                pointProche = PointLineSegmentDistance2D(pa2d, pb2d, qa2d)
                if pointProche[0] < arrondi:
                    pt = point2dVers3d(pointProche[1])
                    spline2.SetPoint(arete2[1], mgi2 * pt)
                    aretesAModifier[i].append(mgi * pt)

                pointProche = PointLineSegmentDistance2D(pa2d, pb2d, qb2d)
                if pointProche[0] < arrondi:
                    pt = point2dVers3d(pointProche[1])
                    spline2.SetPoint(arete2[2], mgi2 * pt)
                    aretesAModifier[i].append(mgi * pt)

                pointProche = PointLineSegmentDistance2D(qa2d, qb2d, pa2d)
                if pointProche[0] < arrondi:
                    pt = point2dVers3d(pointProche[1])
                    spline.SetPoint(arete[1], mgi * pt)
                    aretesAModifier[j].append(mgi2 * pt)

                pointProche = PointLineSegmentDistance2D(qa2d, qb2d, pb2d)
                if pointProche[0] < arrondi:
                    pt = point2dVers3d(pointProche[1])
                    spline.SetPoint(arete[2], mgi * pt)
                    aretesAModifier[j].append(mgi2 * pt)

        # Ajout des nouveaux points

        def pointsToDic(_pts, precision):
            dic = {}
            for p in _pts:
                dic[(int(round(p.x / precision)), int(round(p.z / precision)))] = p
            return dic

        spline = None
        splinePrec = None
        segmentPrec = None
        nouveauxPoints = []
        nouveauxSegments = [0]

        def finaliser(spline, nouveauxSegments, nouveauxPoints):
            nbPts = len(nouveauxPoints)
            spline.ResizeObject(nbPts, len(nouveauxSegments))
            for i, segmentNbPts in enumerate(nouveauxSegments):
                spline.SetSegment(i, segmentNbPts, False)
            spline.SetAllPoints(nouveauxPoints)
            spline.Message(c4d.MSG_UPDATE)

        for i, pointsEnPlus in enumerate(aretesAModifier):

            arete = aretes[i]

            spline = objs[arete[0]]
            if splinePrec is None: splinePrec = spline

            segment = arete[3]
            if segmentPrec is None: segmentPrec = segment

            areteDeFermeture = arete[4]
            derniereArete = arete[5]

            a = arete[1]
            b = arete[2]

            if splinePrec != spline:
                finaliser(splinePrec, nouveauxSegments, nouveauxPoints)
                nouveauxPoints = []
                nouveauxSegments = [0]
            elif segmentPrec != segment:
                nouveauxSegments.append(0)

            if not areteDeFermeture:

                prem = spline.GetPoint(a)
                pointsEnPlus.append(prem)
                if derniereArete:
                    pointsEnPlus.append(spline.GetPoint(b))

                # Supprime les doublons
                pointsEnPlus = list(pointsToDic(pointsEnPlus, precision).values())

                # Tri par position par rapport au premier point
                pointsEnPlus.sort(key=lambda x: (prem - x).GetLengthSquared())

                for pt in pointsEnPlus:
                    nouveauxPoints.append(pt)
                    nouveauxSegments[-1] += 1

            else:
                # Tri par position par rapport au premier point
                pointsEnPlus.sort(key=lambda x: -(prem - x).GetLengthSquared())

                for pt in pointsEnPlus:
                    nouveauxPoints.append(pt)
                    nouveauxSegments[-1] += 1

            splinePrec = spline
            segmentPrec = segment

        finaliser(spline, nouveauxSegments, nouveauxPoints)


Intersection Splines

Modification d'un objet
    @staticmethod
    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)


BruiteObjet

    @staticmethod
    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

            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)


Lissage Catmull Clark

    @staticmethod
    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


Recopie Objet
    @staticmethod
    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)


Optimiser
    @staticmethod
    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)


Aligner Normales
    @staticmethod
    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)


Inverser Normales
    @staticmethod
    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)


Trianguler
    @staticmethod
    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)


Quadranguler
    @staticmethod
    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)


Subdiviser

    @staticmethod
    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)


Fermer Trous

    @staticmethod
    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)


Biseauter Commande
    @staticmethod
    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


Biseauter C4D
    @staticmethod
    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 C4D
    @staticmethod
    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


Extruder

    @staticmethod
    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


Reduction De Polys

    @staticmethod
    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)


Supprimer Polygones
Opérations sur les polygones
    @staticmethod
    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]


Arete Opposee

    @staticmethod
    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


Arete Adjacente

    @staticmethod
    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)
        )


Liste Aretes Polygone

    @staticmethod
    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)
        )


Liste Aretes Polygone Sens ABCD

    @staticmethod
    def QuadrangleEstConvexe(a, b, c, d) :

        """
            Détermine si un quadrangle est convexe ou concave.

            Paramètres :
                a (Vector) - Point A
                b (Vector) - Point B
                c (Vector) - Point C
                d (Vector) - Point D

            Renvoie :
                (bool) - True si le quadrangle est convexe
        """

        nabc = (a - c).Cross(b - c)
        nacd = (a - d).Cross(c - d)

        if nabc.Dot(nacd) < 0 : return False

        nabd = (a - d).Cross(b - d)
        ndbc = (d - c).Cross(b - c)

        if nabd.Dot(ndbc) < 0 : return False

        return True


Quadrangle Est Convexe

    @staticmethod
    def CalculeCercleDansTriangleIsocele(a, b, c):

        """
            Calcule le cercle passant par B et C dans un triangle isocèle en A

            Paramètres :
                a (Vector) - Point A
                b (Vector) - Point B
                c (Vector) - Point C

            Renvoie :
                (Vector) - Position du cercle
                (float) - Rayon du cercle
        """

        c = (b + c) * 0.5

        acN = (c - a).GetNormalized()

        bc2 = (c - b).GetLengthSquared()
        ac = (c - a).GetLength()

        if ac == 0.0: return c, 0.0

        cd = bc2 / ac

        d = c + acN * cd

        return d, (d - b).GetLength()


Calcule un Cercle Dans un Triangle Isocèle

Opérations sur les matrices
    @staticmethod
    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()


Transpose Matrice
Opérations sur les vecteurs
    @staticmethod
    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


Reflete Vecteur

    @staticmethod
    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


Projette Vecteur

    @staticmethod
    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


Rejette Vecteur

    @staticmethod
    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


Transforme Vecteur

    @staticmethod
    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)


Intersection Segments 2D Bool

    @staticmethod
    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. :
        if rxs == 0. :
            return None

        t = CrossScal((q - p), s) / rxs
        u = qpxr / rxs

        # if (0 <= t and t <= 1) and (0 <= u and u <= 1) :
        if (0 <= t <= 1) and (0 <= u <= 1) :
            return p + t*r

        return None


Intersection Segments 2D Vector

    @staticmethod
    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.


Intersection Droites 2D Bool

    @staticmethod
    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


Intersection Droites 2D Vector

    @staticmethod
    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)


Point Est Dans Triangle 2D
Interpolations
    @staticmethod
    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


Interpole Dans Tab
    @staticmethod
    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
                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
        """

        # nbMU = nb - 1.0
        # res = Vector()
        #
        # for i in xrange(nb) :
        #     fac = 1.0 - utils.ClampValue( abs(t * nbMU - i), 0.0, 1.0 )
        #     res += pts[i] * fac
        # return res

        a, b, f = Utils.InterpoleDansTab(nb, t)

        return (1.0 - f) * pts[a] + f * pts[b]


Interpole Lineaire
    @staticmethod
    def 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
                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
        """

        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]


Interpole Doux
    @staticmethod
    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)


Interpole Bezier Quadratique
    @staticmethod
    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


Courbe Bezier Quadratique
Sélections
    @staticmethod
    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


Base Select Aretes Toutes
    @staticmethod
    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


Base Select Polys Depuis Aretes

    @staticmethod
    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


Base Select Polys Tous
    @staticmethod
    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)


Selectionne Points Tous
    @staticmethod
    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)


Selectionne Points Polys Points

    @staticmethod
    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)


Selectionne Polys Tous
    @staticmethod
    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)


Selectionne Polys Inverse
    @staticmethod
    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)


Selectionne Aretes Toutes
    @staticmethod
    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)


Selectionne Aretes Inverse
    @staticmethod
    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()


Selectionne Aretes Aucune
    @staticmethod
    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

        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)


Selectionne Aretes Contour

    @staticmethod
    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


Marquage Points Depuis Aretes

    @staticmethod
    def AffichePolysTous(obj) :

        """
            Affiche tous les polygones.

            Paramètres :
                obj (PolygonObject) - Objet
        """

        if obj.CheckType(c4d.Opolygon) :
            bs = obj.GetPolygonH()
            bs.DeselectAll()


Affiche Polys Tous
    @staticmethod
    def AffichePointsTous(obj) :

        """
            Affiche tous les polygones.

            Paramètres :
                obj (PolygonObject) - Objet
        """

        if obj.CheckType(c4d.Opolygon) :
            bs = obj.GetPointH()
            bs.DeselectAll()


Affiche Points Tous
    @staticmethod
    def AfficheAretesToutes(obj) :

        """
            Affiche toutes les arêtes.

            Paramètres :
                obj (PolygonObject) - Objet
        """

        if obj.CheckType(c4d.Opolygon) :
            bs = obj.GetEdgeH()
            bs.DeselectAll()


Affiche Aretes Toutes
Débug

        return True
Debug Vecteur
    @staticmethod
    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)


Debug Texte
person
create
Les plus récents
keyboard_arrow_down
chuanzhen Thanks for sharing, it helped me a lot, great job! 26 Novembre 2023 05:06
César Vonc Thanks ! 02 Janvier 2022 18:09
Miguel Great work! THank you for share! 02 Janvier 2022 11:57