/**
* @file perspective_types.h
* @brief Types pour Perspective3D.
* @author Florian Joncour
* @date 2013-2018
* @copyright Ces sources font partie de l'interface de programmation pour la bibliothèque Perspective3D,
un outils de modélisation 3D à partir de vues orthographiques 2D.
Ces sources sont fournies à titre gracieux, l'utilisateur a la liberté de les exploiter
pour créer des applications dérivées à condition de respecter les conditions suivantes:

    1) Ces sources ne peuvent être modifiées.
    2) Le dérivé ne peut être exploité à des fins commerciaux.
    3) Aucune licence commerciale de la bibliothèque dont est tiré ce fichier ne peut être rendue publique.
    4) Toute application exploitant la présente bibliothèque doit explicitement faire mention de l'usage et du rôle de Perspective3D.

Ces conditions peuvent toutefois être modifiées avec l'accord de l'auteur.
*/

#ifndef PERSPECTIVE_TYPES_H
#define PERSPECTIVE_TYPES_H

#include "perspective_sys.h"
#include "perspective_def.h"
#include <vector> // std::vector

namespace Perspective3D
{
    /*! Identifiants de résultats de generation 3D. */
    enum class resultat_gen3d_t : pulong
    {
        /*! Rien à générer. */
        PGEN_NUL = 0,
        /*! La génération semble correct. */
        PGEN_OK = 1,
        /*! Erreur inconnue. */
        PGEN_ERR_INCONNUE = 2,
        /*! La génération est valide, mais la clé de licence n'est pas valide (ou non fournie). */
        PGEN_VERROU_LICENCE = 4,
        /*! La génération a été bloquée car la clé de licence n'est pas valide (ou non fournie). */
        PGEN_ERREUR_LICENCE = 8,
        /*! Erreur d'alignement, le problème vient probablement d'un décalage des origines ou de vues non concordantes. */
        PGEN_ERR_ALIGNEMENT_VUES = 16,
        /*! Erreur d'alignement entre la vue de face et de côté (axe Y). */
        PGEN_ERR_ALIGNEMENT_VUES_FACE_COTE = 32,
        /*! Erreur d'alignement entre la vue de face et de dessus (axe X). */
        PGEN_ERR_ALIGNEMENT_VUES_FACE_HAUT = 64,
        /*! Erreur d'alignement entre la vue de côté et de dessus (axe X côté / Y dessus). */
        PGEN_ERR_ALIGNEMENT_VUES_COTE_HAUT = 128,
        /*! Erreur de correspondance des vues, typiquement au moins l'une d'elle a un taille ne correspondant pas avec ses voisines. */
        PGEN_ERR_CORRESPONDANCE_VUES = 256,
        /*! Erreur de correspondance entre la vue de face et de côté. */
        PGEN_ERR_CORRESPONDANCE_VUES_FACE_COTE = 512,
        /*! Erreur de correspondance entre la vue de face et de dessus. */
        PGEN_ERR_CORRESPONDANCE_VUES_FACE_HAUT = 1024,
        /*! Erreur de correspondance entre la vue de côté et de dessus. */
        PGEN_ERR_CORRESPONDANCE_VUES_COTE_HAUT = 2048,
        /*! Erreur, la vue de face est vide. */
        PGEN_ERR_VUEFACE_NULLE = 4096,
        /*! Erreur, la vue de côté est vide. */
        PGEN_ERR_VUECOTE_NULLE = 8192,
        /*! Erreur, la vue de dessus est vide. */
        PGEN_ERR_VUEHAUT_NULLE = 16384,
        /*! Erreur, la vue d'extrusion (typiquement face) est vide. */
        PGEN_ERR_VUEEXTRUSION_NULLE = 32768,
        /*! Erreur, la vue de révolution (typiquement côté) est vide. */
        PGEN_ERR_VUEREVOLUTION_NULLE = 65536,
        /*! Erreur lors de la conversion 2D->3D. Voir le journal de génération. */
        PGEN_ERR_CONVERSION3D = 131072,
        /*! Erreur lors du traitement strictement 3D. Voir le journal de génération. */
        PGEN_ERR_GENERATION3D = 262144
    };
    PENUM_DECL_OPS(resultat_gen3d_t)

    /*! Modes de fonctionnement pour Perspective3D. */
    enum class modeperspective_t : pushort
    {
        /*! Indéfini. */
        PMODE_NUL=0,
        /*! Mode standard (3 vues). */
        PMODE_3VUES,
        /*! Mode extrusion. */
        PMODE_EXTRUSION,
        /*! Mode révolution. */
        PMODE_REVOLUTION
    };
    PENUM_DECL_OPS(modeperspective_t)

    /*! Identifiants des vues où sont placés chacune des entités. */
    enum class vues2D_t : pushort
    {
        /*! Erreur */
        VUERREUR=0,
        /*! Vue inconnue */
        VUENUL=1,
        /*! Vue de face */
        VUEFACE=2,
        /*! Vue de côté */
        VUECOTE=4,
        /*! Vue de dessus */
        VUEHAUT=8,
        /*! Vues indéfinies, à extraire avec la séparatrice PerspectiveVuesAuto */
        VUEMULT=16
    };
    PENUM_DECL_OPS(vues2D_t)

    /*! Identifiants des axes orthographiques 3D. */
    enum class axesOrthos3D_t : pushort
    {
        /*! Indéfini. */
        ORTHO_NUL=0,
        /*! Axe X. */
        ORTHO_X=1,
        /*! Axe Y. */
        ORTHO_Y=2,
        /*! Axe Z. */
        ORTHO_Z=4,
        /*! Axe X négatif. */
        ORTHO_X_N=8,
        /*! Axe Y négatif. */
        ORTHO_Y_N=16,
        /*! Axe Z négatif. */
        ORTHO_Z_N=32
    };
    PENUM_DECL_OPS(axesOrthos3D_t)

    /*! Paramètres d'export pour les fichiers DXF. */
    enum class params_export_dxf_t : pushort
    {
        EXPORT_DXF_NUL=0,
        /*! Export du modèle filaire. */
        EXPORT_DXF_FILAIRE=1,
        /*! Désactivation de l'export des surfaces. */
        EXPORT_DXF_SOLIDE_NUL=2,
        /*! Export du solide sous forme de maillage (sommets->segments->surfaces) avec l'entitée MESH. Chaque solide sera dans un maillage différent. */
        EXPORT_DXF_SOLIDE_MESH=4,
        /*! Export du solide sous forme de maillage (sommets->segments->surfaces) avec l'entitée MESH. L'ensemble des solides seront sur le même mailage. */
        EXPORT_DXF_SOLIDE_MESH_GROUPE=8,
        /*! Export du solide l'entitée 3DFACE. Aucun maillage, le solide sera divisé en triangles. */
        EXPORT_DXF_SOLIDE_FACES=16
    };
    PENUM_DECL_OPS(params_export_dxf_t)

    /**
     * @brief PStdVectInts Vecteur d'entiers.
     */
    typedef std::vector<int> PStdVectInts;

    /**
     * @brief Identifiants des entitées.
     */
    typedef pint32 pident;

    /*! Norme des vues Indéfini/ISO/US. Sert pour connaitre le type de projections afin de construire le solide. */
    enum class normevues_t : pushort
    {
        NORME_VUES_NUL=0,
        /*! Mode vues ISO. */
        NORME_VUES_ISO,
        /*! Mode vues Nord-Américain. */
        NORME_VUES_US
    };
    PENUM_DECL_OPS(normevues_t)

    namespace i18n
    {
        /*! Langues internes à Perspective3D (pour le journal et les couleurs RAL). */
        enum class lang_p3d_t : pushort
        {
            /*! Français */
            P3D_LANG_FR=0,
            /*! Anglais */
            P3D_LANG_EN
        };
        PENUM_DECL_OPS(lang_p3d_t)
        #define P3D_LANG_DEFAUT Perspective3D::i18n::lang_p3d_t::P3D_LANG_EN
    }

    /*! Identifiants des informations à afficher sur le solide 3D. */
    enum class infos3d_t : pushort
    {
        INUL=0,
        ITOUT=1,
        /*! Affichage des identifiant des sommets. */
        IDPOINTS=2,
        /*! Affichage des identifiant des segments. */
        IDLIGNES=4,
        /*! Affichage des coordonnées des sommets. */
        ICOORDSPOINTS=8,
        /*! Affichage des vecteurs normaux des surfaces. */
        IVECTEURNORM=16,
        /*! Affichage des valeurs des vecteurs normaux des surfaces. */
        IVALNORMAUX=32,
        /*! Affichage des identifiant des surfaces. */
        IDSURFACES=64,
        /*! Affichage des identifiant des courbes. */
        IDCOURBES=128,
        /*! Affichage des identifiant des sphères. */
        IDSPHERES=256
    };
    PENUM_DECL_OPS(infos3d_t)

    /*! Paramètres de génération 3D. */
    enum class params_gen3d_t : pushort
    {
        PGEN3DNUL=0,
        /*! Réduction de la complexité des surfaces. */
        DIVISION_SURF=1,
        /*! Contrôle de l'enveloppe du solide. */
        CONTROLE_ENVELOPPE=2,
        /*! Suppression des segments orphelins. */
        SUPPR_LIGNES_ORPHELINES=4,
        /*! Suppression des alignements de segments. */
        SUPPR_ALIGNEMENT_LIGNES=8,
        /*! Suppression des chevauchement de segments. */
        SUPPR_CHEVAUCHEMENT_LIGNES=16,
        /*! Suppression des croisements de segments. */
        SUPPR_CROISEMENT_LIGNES=32,
        /*! Suppression des surfaces voisines et de même plan. */
        SUPPR_VOISINES_MEME_PLAN=64,
        /*! Supprime les surfaces des surfaces croisant un ou plusieurs segments. */
        SUPPR_COLLISION_LIGNES_SURFACES=128,
        /*! Suppression des segments dont toutes les connexions sont sur le même plan. */
        SUPPR_CROISEMENT_LIGNES_PLAN=256,
        /*! Conservation dans un modèle parallèle des entités supprimées. */
        CONSERVATION_SUPPRS=512
    };
    PENUM_DECL_OPS(params_gen3d_t)

    /*! Proprietes des entités 3D. */
    enum class proprietes_3d_t : puint8
    {
        PROPRIETE_3D_NUL=0,
        PROPRIETE_3D_COURBE=1,
        PROPRIETE_3D_TROU=2,
    };
    PENUM_DECL_OPS(proprietes_3d_t)

    /*! Proprietes des entités 2D. */
    enum class proprietes_2d_t : puint8
    {
        PROPRIETE_2D_NUL=0,
        PROPRIETE_2D_CACHE=1,
    };
    PENUM_DECL_OPS(proprietes_2d_t)


    typedef puint8 Poctet_t;

    /**
     * @brief Définition d'un point 2D et de ses opérations.
     */
    class DLL_API Ppoint2D : public PBase
    {
        public:
            inline explicit Ppoint2D(pfloat x_=COORD0, pfloat y_=COORD0) {x=x_; y=y_;}

            inline void defX(pfloat x_) { x=x_; }
            inline void defY(pfloat y_) { y=y_; }
            inline void defXY(pfloat x_, pfloat y_) { x=x_, y=y_; }
            inline pfloat X() const { return x; }
            inline pfloat Y() const { return y; }
            inline pfloat &refX() { return x; }
            inline pfloat &refY() { return y; }

            inline Ppoint2D &operator+=(const pfloat s) { x+=s; y+=s; return *this; }
            inline Ppoint2D &operator-=(const pfloat s) { x-=s; y-=s; return *this; }
            inline Ppoint2D &operator*=(const pfloat s) { x*=s; y*=s; return *this; }
            inline Ppoint2D &operator/=(const pfloat s) { x/=s; y/=s; return *this; }
            inline Ppoint2D &operator*=(const Ppoint2D &v) { x*=v.X(); y*=v.Y(); return *this; }
            inline Ppoint2D &operator/=(const Ppoint2D &v) { x/=v.X(); y/=v.Y(); return *this; }
            inline Ppoint2D &operator+=(const Ppoint2D &v) { x+=v.X(); y+=v.Y(); return *this; }
            inline Ppoint2D &operator-=(const Ppoint2D &v) { x-=v.X(); y-=v.Y(); return *this;}

            inline Ppoint2D operator+(const pfloat s) const { return Ppoint2D(x+s, y+s); }
            inline Ppoint2D operator-(const pfloat s) const { return Ppoint2D(x-s, y-s); }
            inline Ppoint2D operator*(const pfloat s) const { return Ppoint2D(x*s, y*s); }
            inline Ppoint2D operator/(const pfloat s) const { return Ppoint2D(x/s, y/s); }
            inline Ppoint2D operator*(const Ppoint2D &v) const { return Ppoint2D(x*v.X(), y*v.Y()); }
            inline Ppoint2D operator/(const Ppoint2D &v) const { return Ppoint2D(x/v.X(), y/v.Y()); }
            inline Ppoint2D operator+(const Ppoint2D &v) const { return Ppoint2D(x+v.X(), y+v.Y()); }
            inline Ppoint2D operator-(const Ppoint2D &v) const { return Ppoint2D(x-v.X(), y-v.Y()); }

            /**
             * @brief Normalise le vecteur.
             */
            void normalise();

            /**
             * @brief Renvoi le vecteur normal du point courant vers le point v2
             */
            inline Ppoint2D norme(const Ppoint2D &v2) const
            {
                Ppoint2D r(v2.x - x, v2.y - y);
                r.normalise();
                return r;
            }

            /**
             * @brief operator < Comparaison entre deux points avec l'Epsilon dynamique.
             */
            inline bool operator<(const Ppoint2D& v) const
            {
                if (CompareED(x, v.x))
                {
                    if (CompareED(y, v.y)) // Egalitée
                    {
                        return false;
                    }
                    return (y < v.y);
                }
                return (x < v.x);
            }

            /**
             * @brief operator != Comparaison entre deux points avec l'Epsilon fixe.
             */
            inline bool operator!=(const Ppoint2D &v) const { return !CompareED(x, v.x) || !CompareED(y, v.y); }

            /**
             * @brief operator == Comparaison entre deux points avec l'Epsilon fixe.
             */
            inline bool operator==(const Ppoint2D &v) const { return CompareED(x, v.x) && CompareED(y, v.y); }

            /**
             * @brief Distance2 Distance au carré entre deux points.
             * @param p Le point voisin.
             */
            inline pfloat Distance2(const Ppoint2D &p) const { return ( POW2(POSITIFD(x - p.X())) + POW2(POSITIFD(y - p.Y())) ); }

            /**
             * @brief centre Renvoi le centre entre deux sommets.
             */
            inline Ppoint2D centre(const Ppoint2D &p) const { return Perspective3D::Ppoint2D( ((x+p.x)*0.5), ((y+p.y)*0.5 ) ); }

            /**
             * @brief Distance Distance entre deux points.
             * @param p Le point voisin.
             */
            inline pfloat Distance(const Ppoint2D &p) const { return RCARREF(Distance2(p)); }

            /**
             * @brief dot Produit scalaire.
             */
            inline pfloat dot(const Ppoint2D &v) const { return (X()*v.X()) + (Y()*v.Y()); }

            inline pfloat at(puint i) const
            {
                return (i==0) ? x : ((i==1) ? y : -1);
            }

            inline static size_t numDim() { return 2; }

        protected:
            pfloat x;
            pfloat y;
    };

    /**
     * @brief PStdVectPoints2D Vecteur de points 2D.
     */
    typedef std::vector<Ppoint2D> PStdVectPoints2D;

    /**
     * @brief Représente un pixel.
     */
    class DLL_API PPixel : public PBase
    {
        public:
            inline explicit PPixel() : r(0), v(0), b(0), alpha(255) { }
            inline explicit PPixel(Poctet_t r_, Poctet_t v_, Poctet_t b_, Poctet_t a=255) : r(r_), v(v_), b(b_), alpha(a) { }
            inline explicit PPixel(puint32 v) { defIRVB(v); }

            inline PPixel(const PPixel &p) : r(p.r), v(p.v), b(p.b), alpha(p.alpha) { } /* Constructeur de copie. */

            inline bool Nulle() const { return (!r && !v && !b); }
            inline void defNulle() { r=v=b=0; }

            inline bool operator==(const PPixel &c) const { return ((r == c.R()) && (v == c.V()) && (b == c.B())); }

            inline Poctet_t R() const { return r; }
            inline Poctet_t V() const { return v; }
            inline Poctet_t B() const { return b; }

            inline Poctet_t Alpha() const { return alpha; }

            inline void defR(Poctet_t rouge) { r=rouge; }
            inline void defV(Poctet_t vert) { v=vert; }
            inline void defB(Poctet_t bleu) { b=bleu; }
            inline void defRVB(Poctet_t rouge, Poctet_t vert, Poctet_t bleu) { r=rouge; v=vert; b=bleu; }
            inline void defRVBA(Poctet_t rouge, Poctet_t vert, Poctet_t bleu, Poctet_t opacite) { r=rouge; v=vert; b=bleu; alpha=opacite; }
            inline void defAlpha(Poctet_t a) { alpha=a; }

            inline puint32 RVBi() const { return (( (static_cast<puint32>(r)) << 16 ) | ( (static_cast<puint32>(v)) << 8 ) | ( (static_cast<puint32>(b)) & 0xff )); }
            inline void defIRVB(puint32 i) { r = (i >> 16) & 0xff; v = (i >> 8) & 0xff; b = (i) & 0xff; alpha = (i >> 24); }

            void toHSV(pfloat *val_h, pfloat *val_s, pfloat *val_v) const;
            void toHSV(pfloat hsv[]) const;

            void fromHSV(pfloat val_h, pfloat val_s, pfloat val_v);
            void fromHSV(const pfloat hsv[]);

        protected:
            Poctet_t r, v, b;
            Poctet_t alpha;
    };

    /**
     * @brief PStdVectPoints2D Vecteur de pixels
     */
    typedef std::vector<PPixel> PStdVectPixels;

    /**
     * @brief Représente les coordonnés un pixel.
     */
    class DLL_API PPointPixel : public PBase
    {
        public:
            inline explicit PPointPixel(pint x_, pint y_) : x(x_), y(y_) { }
            inline explicit PPointPixel() : x(0), y(0) { }

            inline pint X() const { return x; }
            inline pint Y() const { return y; }

            inline void defX(pint x_) { x=x_; }
            inline void defY(pint y_) { y=y_; }
            inline void defXY(pint x_, pint y_) { x=x_; y=y_; }

            inline bool Nul() const { return !x && !y; }

            inline bool operator==(const PPointPixel &p) const
            { return (x == p.x) && (y == p.y); }

            inline bool operator!=(const PPointPixel &p) const
            { return (x != p.x) || (y != p.y); }

            inline Ppoint2D Point2D() const
            {
                return Ppoint2D(pfloat(x), pfloat(y));
            }

        protected:
            pint x, y;
    };

    /**
     * @brief PStdVectPoints2D Vecteur de points de pixels
     */
    typedef std::vector<PPointPixel> PStdVectPointsPixels;

    /**
     * @brief Couleur du nuancier RAL classique.
     */
    class DLL_API PCouleur_RAL // : public PBase
    {
        public:
            pushort id;
            Poctet_t r;
            Poctet_t v;
            Poctet_t b;
            const char *nom;
    };

    /**
     * @brief Couleurs 32 bits
     */
    class DLL_API PCouleur : public PPixel
    {
        public:
            inline explicit PCouleur(): PPixel(), actif(true), div(false) { ; }
            inline explicit PCouleur(const PPixel &p): PPixel(p), actif(true), div(false) { ; }
//            inline explicit PCouleur(const PCouleur &c): r(c.r), v(c.v), b(c.b), actif(c.actif) { ; }
            inline explicit PCouleur(const PCouleur_RAL &ral, bool actif_=true) : PPixel(ral.r, ral.v, ral.b), actif(actif_), div(false) { ; }
            inline explicit PCouleur(Poctet_t rouge, Poctet_t vert, Poctet_t bleu, bool actif_=true) : PPixel(rouge, vert, bleu), actif(actif_), div(false) { ; }
            inline explicit PCouleur(Poctet_t gris, bool actif_=true) : PPixel(gris, gris, gris), actif(actif_), div(false) { ; }

            explicit PCouleur(const vues2D_t vue);

            inline bool operator==(const PCouleur &c) const { return ((r == c.R()) && (v == c.V()) && (b == c.B())); }

            inline bool Actif() const { return actif; }
            inline void defActif(bool a=true) { actif=a; }
            inline PCouleur Inverse() const { const Poctet_t maxchar=255; return PCouleur(maxchar-r, maxchar-v, maxchar-b, actif); }

            inline PPixel Pixel() const { return PPixel(r, v, b, alpha); }

            PCouleur Restaure();
            PCouleur Div();
            PCouleur Div2();

        protected:
            bool actif;
            bool div;
    };

    /**
     * @brief ParametresPerspective Paramètres de la bibliothèque Perspective.
     * @param langue La langue à utiliser pour le journal.
     * @param tolerance la valeur de tolérance aux erreurs (valeur maximum pour considérer deux coordonnées comme égales).
     * @param arrondi_dessin Valeur d'arrondi pour calculer l'epsilon (en nombre de chiffres après la virgule), c'est à dire E=10^(-arrondi_dessin).
     * @param divisionscercles Nombre de divisions en segments pour les entitées courbes (arcs, ellipses, cercles, etc...).
     * @param projections Défini les vues 2D que l'on souhaite projecter sur le solide 3D (vues2D_t::VUEFACE, vues2D_t::VUECOTE, vues2D_t::VUEHAUT).
     * @param informations Défini les informations que l'on souhait voir apparaitre sur le solide 3D (voir l'espace de nom INFOS3D).
     * @param tailletexte3d Taille du texte 3D affiché sur le solide 3D (en % de la taille de la scène qui sera générée).
     * @param filaire_uniquement Si true, seul le modèle filaire sera généré.
     * @param parametres3d Parametres pour le traitement strictement 3D (voir l'espace de nom PARAMS_GEN3D).
     * @param taille_surfaces Nombre de sommets maximum pour chaque surfaces.
     * @param norme_vues défini la norme du rapport entre les vues utilisé (voir l'enum ::normevues_t et pour les non dessinateurs: http://fr.wikipedia.org/wiki/Dessin_technique).
     * @param id_ral défini la couleur (identifiant RAL) à appliquer sur le solide.
     * @param licence Chaine de caractère contenant la clé d'activation du logiciel (chiffrée avec la fonction ChiffrementLicence()) pour débloquer toutes les fonctionnalités. Si nul ou invalide, la bibliothèque sera en mode démo.
     */
    struct DLL_API ParametresPerspective
    {
            ParametresPerspective(pfloat tolerance=0.001, pint arrondi_dessin=3, pint divisionscercles=24, vues2D_t projections=vues2D_t::VUEFACE|vues2D_t::VUECOTE|vues2D_t::VUEHAUT, infos3d_t informations=infos3d_t::INUL, pint tailletexte3d=8, bool filaire_uniquement=false, bool multithreading=false, params_gen3d_t parametres3d=params_gen3d_t::PGEN3DNUL, puint taille_surfaces=256, normevues_t norme_vues=normevues_t::NORME_VUES_ISO, puint id_ral=9010, const pint8 *licence=nullptr, puint64 salage_licence=0) :
                Tolerance(tolerance), Arrondi_dessin(arrondi_dessin), Divisionscercles(divisionscercles), Projections(projections), Informations(informations), Tailletexte3d(tailletexte3d), TailleDiagoUniforme(0), Filaire_uniquement(filaire_uniquement), MultiThreading(multithreading), Parametres3d(parametres3d), Taille_surfaces(taille_surfaces), Norme_vues(norme_vues), Id_ral(id_ral), Licence(licence), SalageLicence(salage_licence)
            {
                ;
            }

            pfloat Tolerance;
            pint Arrondi_dessin;
            pint Divisionscercles;
            vues2D_t Projections;
            infos3d_t Informations;
            pint Tailletexte3d;
            puint TailleDiagoUniforme;
            bool Filaire_uniquement;
            bool MultiThreading;
            params_gen3d_t Parametres3d;
            puint Taille_surfaces;
            normevues_t Norme_vues;
            puint Id_ral;
            const pint8 *Licence;
            puint64 SalageLicence;
    };

#ifdef SUPPORT_VISION2D
    /**
     * @brief ParametresPerspective Paramètres de la bibliothèque Vision.
     */
    struct DLL_API ParametresVision
    {
        puint SeuilActivation; /* Seuil d'activation des pixels (de 0 à 255) */
        bool ContourSegments; /* Type de réduction (contour extérieur ou rétrécissement) */
        PPixel CouleurTrace; /* Couleur du tracé. */
        pfloat EpsilonCoords;       /* Distance d'approximation pour considérer deux coordonnées comme semblables (version précise). */
        pfloat ToleranceCoords1;    /* Distance d'approximation pour considérer deux coordonnées comme semblables (version moyennement précise). */
        pfloat ToleranceCoords2;    /* Distance d'approximation pour considérer deux coordonnées comme semblables (version très approximative). */
        pfloat ToleranceAngles;     /* Différence d'approximation pour considérer deux angles comme semblables. */
        pfloat ToleranceJointures;
        pfloat ToleranceCourbure; /* Tolérance pour contrôle de la courbure par rapport aux segments représentant la courbe. */
        pfloat ToleranceJointuresCentreCourbes; /* Tolérance de contrôle du centre pour joindre deux courbes. */
        pfloat DeltaCourbesMin; /* Delta minimum pour accepter un arc de courbe. */
        pfloat DeltaCourbesMax; /* Delta maximum pour accepter un arc de courbe. */
        pfloat ToleranceNorms; /* Seuil de tolérance à appliquer pour la comparaison des vecteurs normaux. */
        pfloat DeltaAnglesCourbesMin;
        pfloat DeltaAnglesCourbesMax;
        pfloat TailleGrille; /* Taille de la grille pour l'alignement des entités (optionnel) */
        const pint8 *Licence;
        puint64 SalageLicence;
    };

    /*! Identifiants de résultats de generation 3D. */
    enum class resultat_vision2d_t : pulong
    {
        /*! La génération semble correct. */
        V2D_OK=0,
        /*! Au moins une entitée a été généré, mais assemblée dans un groupe précédent, tandis que le nouveau groupe est vide. */
        V2D_ASSEMBLAGE=1,
        /*! La erreur inconnue. */
        V2D_ERR_INCONNUE=2,
        /*! Seuil nombre maximum d'entités atteint (d'après la licence utilisateur). */
        V2D_MAX_ENTITES_LICENCE=4,
        /*! Groupe pour recevoir les entités invalide. */
        V2D_ERR_GROUPE=8,
        /*! Débordement sur la matrice, l'image est probablement trop dense. */
        V2D_DEPASSEMENT_CAPACITE=16,
        /*! Matrice invalide, cela veut probablement dire qu'elle est trop petite et qu'il est impossible d'en extraire des entités. */
        V2D_MATRICE_INVALIDE=32,
        /*! Il n'y a rien à générer. */
        V2D_TRACE_NUL=64
    };
    PENUM_DECL_OPS(resultat_vision2d_t)

#endif // SUPPORT_VISION2D

    /**
     * @brief Classe d'image 32 bits (RBVA). Peut gérer un tableau dynamique ou englober un tableau statique suivant le constructeur appelé.
     * La copie est rapide puisqu'elles se fait par manipulation de pointeurs.
     * Dans le cas d'une allocation dynamique, l'instance de la dernière copie effectuée appelera le destructeur du vecteur.
     */
    class DLL_API PImage : public PBase
    {
            friend class PImagePriv;

        public:
            explicit PImage(puint largeur_, puint hauteur_);
            explicit PImage(puint largeur_, puint hauteur_, pushort bpp_, const Poctet_t *oct, bool dealloc_memoire=false);

            /**
             * @brief Ouverture d'un fichier image (BMP, PNG, JPEG, GIF, TGA, PSD ou PNM)
             */
            explicit PImage(const char *n);

            /**
             * @brief Ouverture d'un fichier image (BMP, PNG, JPEG, GIF, TGA, PSD ou PNM)
             */
            explicit PImage(const std::string &n);

            /**
             * @brief Création d'une image à partir d'un trajet de pixels (le trajet sera représenté en noir, le remplissage en blanc)
             */
            explicit PImage(const PStdVectPointsPixels &trajet, pfloat echelle=1.0, pint marge=10, const PPixel &couleur_fond=PPixel(255, 255, 255, 255));

            /**
             * @brief Constructeur de copie, désactivera la libération de la mémoire sur l'image source car la mémoire sera partagée.
            */
            PImage(const PImage &img);

            ~PImage();

            /**
             * @brief Export de l'image au format PNG.
             */
            bool ExportPNG(const char *n) const;

            /**
             * @brief Export de l'image au format JPEG.
             */
            bool ExportJPEG(const char *n) const;

            /**
             * @brief Renvoi la taille de chaque pixel en octets (typiquement 3 pour RVB ou 4 pour RVBA).
             */
            pushort TaillePixels() const { return bpp; }

            /**
             * @brief Renvoi la hauteur de l'image.
             */
            puint Hauteur() const { return hauteur; }

            /**
             * @brief Renvoi la largeur de l'image.
             */
            puint Largeur() const { return largeur; }

            /**
             * @brief Renvoi la taille octale de l'image.
             */
            puint Taille() const;

            /**
             * @brief Renvoi la taille de l'image de nombre de pixels.
             */
            puint NombrePixels() const;

            /**
             * @brief Renvoi un pixel à une position donnée (avec calcul du canal Alpha et assimilation à la couleur de fond si défini)
             */
            const PPixel Pixel(pint i) const;

            /**
             * @brief Renvoi un pixel d'après ses coordonnées.
             */
            const PPixel Pixel(pint x, pint y) const;

            /**
             * @brief Contrôle si l'image a été considérée comme valide après génération ou chargement.
             */
            inline bool Valide() const { return valide; }

            /**
             * @brief Opérateur de copie
             */
            PImage& operator=(const PImage &img);

            /**
             * @brief Copie l'image (les deux images seront distinctes et ne partageront donc pas le même tampon mémoire).
             */
            PImage Copie() const;

        protected:
            puint Pos(pint x, pint y) const;

            pushort bpp;
            puint hauteur, largeur;
            PStdVectPixels *pixels;
            Poctet_t const *tampon_oct; /* Cas où l'on englobe un tableau statique */
            bool valide;
            mutable bool dealloc;
    };

    /**
     * @brief Type de base pour gérer les ids des entités graphiques.
     */
    class DLL_API PBaseId : public PBase
    {
        public:
            inline PBaseId(pident id_) : id(id_) { }

            /**
             * @return L'id d'une entité.
             */
            inline pident Id() const { return id; }

            /**
             * @brief Assignation de l'id d'une entité.
             */
            inline void defId(pident i) { id=i; }

            /**
             * @return true si l'id est nul, sinon false.
             */
            inline bool IdNul() const { return id == IDNUL; }

        protected:
            pident id; /* Identifiant de l'entité, doit pour chaque type valoir la position dans le vecteur d'entités (il est donc unique si il n'est pas nul) */
    };

    /**
     * @brief Type de base pour toutes les entités graphiques Perspective3D.
     */
    class DLL_API PEntite : public PBaseId
    {
        public:
            inline PEntite(pident id_) : PBaseId(id_), attributs(0) { }
            inline PEntite(pident id_, puint16 attr) : PBaseId(id_), attributs(attr) { }

            inline puint16 Attributs() const { return attributs; }
            inline puint16 &AttributsRef() { return attributs; }
            inline void ReinitAttributs() { attributs = 0; }
            inline void defAttributs(puint16 att) { attributs=att; }

            inline void AjoutAttribut(puint16 attr) { attributs |= attr; }
            inline void RetireAttribut(puint16 attr) { attributs ^= attr; }
            inline bool ValideAttribut(puint16 attr) const { return attributs & attr; }

            inline void AjoutAttributId(puint16 id) { AjoutAttribut(1<<id); }
            inline void RetireAttributId(puint16 id) { RetireAttribut(1<<id); }
            inline bool ValideAttributId(puint16 id) const { return ValideAttribut(1<<id); }

        protected:
            puint16 attributs; /* Les attributs sont spécifiques à une allocation, ils ne seront pas copiés via les opérateurs de copie. */
    };

    /* <2D> */
    /**
     * @brief Type de base pour les entitées 2D.
     */
    class DLL_API PEnt2D : public PEntite
    {
        public:
            inline PEnt2D(): PEntite(IDNUL), vue(vues2D_t::VUENUL), proprietes(proprietes_2d_t::PROPRIETE_2D_NUL), couleur(PCouleur()) {}
            inline PEnt2D(pident i): PEntite(i), vue(vues2D_t::VUENUL), proprietes(proprietes_2d_t::PROPRIETE_2D_NUL), couleur(PCouleur()) {}

            inline PEnt2D(pident i, vues2D_t v, bool c, const PCouleur&cl) : PEntite(i), vue(v), proprietes(proprietes_2d_t::PROPRIETE_2D_NUL), couleur(cl)
                { defCache(c); }

            inline vues2D_t Vue() const { return vue; }
            inline void defVue(vues2D_t v) { vue=v; }

            inline bool Cache() const { return proprietes & proprietes_2d_t::PROPRIETE_2D_CACHE; }
            inline void defCache(bool c) { if (c != Cache()) { proprietes = ((c) ? (proprietes | proprietes_2d_t::PROPRIETE_2D_CACHE) : (proprietes ^ proprietes_2d_t::PROPRIETE_2D_CACHE)); } }

            inline PCouleur &Couleur() { return couleur; }
            inline const PCouleur &CouleurConst() const { return couleur; }
            inline void defCouleur(const PCouleur &c) { couleur=c; }

            inline void defProprietes(proprietes_2d_t props) { proprietes = props; }
            inline proprietes_2d_t Proprietes() const { return proprietes; }

        protected:
            vues2D_t vue; /* Vue sur laquelle a été dessinée l'entité. */
            proprietes_2d_t proprietes; /* Proprietes. */
            PCouleur couleur;
    };

    /**
     * @brief Définition d'une ligne 2D.
     */
    class DLL_API Pligne2D: public PEnt2D
    {
        public:
            inline Pligne2D(): PEnt2D(), p1(), p2(), point(false) { ; }

            inline Pligne2D(const Ppoint2D &p1_, const Ppoint2D &p2_, pident id_=IDNUL, bool cache_=false, bool point_=false, const PCouleur&c=PCouleur()) : PEnt2D(), p1(p1_), p2(p2_), point(point_)
            {
                defId(id_);
                defCache(cache_); defCouleur(c);
            }

            inline Pligne2D(const Pligne2D &l) : PEnt2D(l.Id(), l.Vue(), l.Cache(), l.CouleurConst()), p1(l.p1), p2(l.p2), point(l.point) { ; }

            inline Pligne2D& operator=(const Pligne2D &l)
            {
                defId(l.Id()); defVue(l.Vue());
                defCache(l.Cache()); defCouleur(l.CouleurConst());
                p1 = l.p1; p2 = l.p2; point = l.point;
                return *this;
            }

            inline Ppoint2D &P1() { return p1; }
            inline const Ppoint2D &P1Const() const { return p1; }
            inline void defP1(const Ppoint2D &p) { p1=p; }
            inline void defP1(pfloat x, pfloat y) { p1.defXY(x, y); }

            inline Ppoint2D &P2() { return p2; }
            inline const Ppoint2D &P2Const() const { return p2; }
            inline void defP2(const Ppoint2D &p) { p2=p; }
            inline void defP2(pfloat x, pfloat y) { p2.defXY(x, y);}

            inline bool Point() const { return point; }
            inline void defPoint(bool p) { point=p; }

            inline pfloat Longueur2() const
            {
                return p1.Distance2(p2);
            }

            inline pfloat Longueur() const
            {
                return p1.Distance(p2);
            }

            bool Nulle() const;

        protected:
            Ppoint2D p1, p2;
            bool point; /* true si la ligne représente un point */
    };

    /**
     * @brief PStdVectLignes2D Vecteur de lignes 2D.
     */
    typedef std::vector<Pligne2D> PStdVectLignes2D;

    /**
     * @brief Rectangle 2D, principalement pour faire des boites englobantes.
     */
    class DLL_API Prect2D : public PEnt2D
    {
        public:
            Prect2D(const Prect2D &r);
            Prect2D(bool init_cadre_englobage=true);
            Prect2D(const Ppoint2D &p1_, const Ppoint2D &p2_);
            Prect2D(pfloat p1x, pfloat p1y, pfloat p2x, pfloat p2y);
            Prect2D& operator=(const Prect2D &r);

            inline void defPmin(const Ppoint2D &p) { pmin = p; }
            inline void defPmax(const Ppoint2D &p) { pmax = p; }

            inline const Ppoint2D &Pmin() const { return pmin; }
            inline const Ppoint2D &Pmax() const { return pmax; }

//            inline const Ppoint2D &P1() const { return pmin; }
//            inline Ppoint2D P2() const { return Ppoint2D(pmin.X()+Largeur(), pmin.Y()); }
//            inline const Ppoint2D &P3() const { return pmax; }
//            inline Ppoint2D P4() const { return Ppoint2D(pmin.X(), pmin.Y()+Hauteur()); }

            inline const Ppoint2D &P1() const { return pmin; }
            inline Ppoint2D P2() const { return Ppoint2D(pmax.X(), pmin.Y()); }
            inline const Ppoint2D &P3() const { return pmax; }
            inline Ppoint2D P4() const { return Ppoint2D(pmin.X(), pmax.Y()); }

            inline pfloat Largeur() const { return pmax.X()-pmin.X(); }
            inline pfloat Hauteur() const { return pmax.Y()-pmin.Y(); }

            inline pfloat Diago() const { return RCARREF(Largeur()*Largeur() + Hauteur()*Hauteur()); }

            inline Ppoint2D Centre() const { return Ppoint2D((pmin.X()+(Largeur()*.5)), (pmin.Y()+(Hauteur()*.5))); }

            bool ContientPoint(const Ppoint2D &p) const;
            /* Le point est contenu dans le rectangle ? */

            bool CollisionRects(const Prect2D &r) const;
            /* r au moins partiellement (1 sommet minimum) dans ce rectangle ? */

            bool CollisionRects2(const Prect2D &r) const;
            /* r au moins partiellement (1 sommet minimum) dans ce rectangle ? (avec tolérance) */

            bool CollisionRectsX(const Prect2D &r, const pfloat tolerance) const;
            /* r au moins partiellement (1 sommet minimum) dans ce rectangle ? (avec tolérance) */

            bool ContientBordRect(const Prect2D &r) const;
            /* r au moins partiellement (2 sommets minimum) dans ce rectangle ? */

            bool ContientTotalementRect(const Prect2D &r) const;
            /* r totalement englobé par ce rectangle ? */

            pfloat Distance(const Ppoint2D &p) const;
            pfloat Distance(const Prect2D &r) const;
            void InvY();

            void InitEnglobage();

            void EnglobePoint(const Ppoint2D &p);
            /* Assigne les coordonnées du point si l'une d'entre elle dépasse p1 ou p2.
            Utilisé pour gérer la boite englobante d'une suite de points. */

            bool Nul() const;

            inline void EnglobeLigne(const Pligne2D &l)
            /* Comme EnglobePoint, mais avec une suite de lignes. */
            {
                EnglobePoint(l.P1Const());
                EnglobePoint(l.P2Const());
            }

            inline void EnglobeRect(const Prect2D &r)
            /* Englobe r dans ce rectangle. */
            {
                EnglobePoint(r.Pmin());
                EnglobePoint(r.Pmax());
            }

            void Dilate(pfloat x, pfloat y);
            /* Effectue un décalage sur la boite englobante (pour l'agrandir ou la rétrécir si les valeurs sont positives ou négatives. */

            void Dilate(pfloat xy);

            void RedefOrigineEnglobage(pfloat x, pfloat y);

            inline bool ValideEnglobage() const { return (pmin.X() < pmax.X() && pmin.Y() < pmax.Y()); }

            inline pfloat Aire() const { return Largeur()*Hauteur(); }

        protected:
            bool CadreEnglobe;
            Ppoint2D pmin, pmax;
    };

    /**
     * @brief PStdVectRect2D Vecteur des rectangles 2D.
     */
    typedef std::vector<Prect2D> PStdVectRect2D;

    /**
     * @brief Définition ellipse, arc ou cercle 2D
     */
    class DLL_API Pellipse2D: public PEnt2D
    {
        public:
            inline Pellipse2D(): PEnt2D(), centre(), lg(COORD0), ht(COORD0), angle1(COORD0), angle2(COORD0), rotation(0.), ferme(true) { ; }

            inline Pellipse2D(const Pellipse2D &e) : PEnt2D(e.Id(), e.Vue(), e.Cache(), e.CouleurConst()),
                centre(e.centre), lg(e.lg), ht(e.ht), angle1(e.angle1), angle2(e.angle2), rotation(e.rotation), ferme(e.ferme) { ; }

            inline Pellipse2D(const Ppoint2D &centre_, pfloat lg_, pfloat ht_, pfloat angle1_, pfloat angle2_, pfloat rotation_=0., pident id_=IDNUL, bool cache_=false):
                PEnt2D(id_), ferme(true)
            {
                ferme = CompareE(POSITIFD(angle2_-angle1_), 360.);
                centre=centre_; lg=lg_; ht=ht_; angle1=angle1_; angle2=angle2_; rotation=rotation_; defCache(cache_);
//                vue = vues2D_t::VUENUL;
            }

            inline Pellipse2D& operator=(const Pellipse2D &e)
            {
                defId(e.Id()); defVue(e.Vue()); defCache(e.Cache()); defCouleur(e.CouleurConst());
                centre = e.centre; lg = e.lg; ht = e.ht; angle1 = e.angle1; angle2 = e.angle2; rotation = e.rotation; ferme = e.ferme;
                return *this;
            }

            inline bool Ferme() const { return ferme; }
            inline void defFerme(bool f) { ferme=f; }

            inline pfloat Rotation() const { return rotation; }
            inline void defRotation(pfloat r) { rotation=r; }

            inline pfloat Angle1() const { return angle1; }
            inline void defAngle1(pfloat a) { angle1=a; }

            inline pfloat Angle2() const { return angle2; }
            inline void defAngle2(pfloat a) { angle2=a; }

            inline pfloat Lg() const { return lg; }
            inline void defLg(pfloat l) { lg=l; }

            inline pfloat Ht() const { return ht; }
            inline void defHt(pfloat h) { ht=h; }

            inline Ppoint2D &Centre() { return centre; }
            inline const Ppoint2D &CentreConst() const { return centre; }
            inline void defCentre(const Ppoint2D &c) { centre = c; }

            Prect2D rectangle() const;

        protected:
            Ppoint2D centre; /* Centre. */
            pfloat lg; /* Longueur (diamètre sens horizontal). */
            pfloat ht; /* Hauteur (diamètre sens vertical, même valeur que lg pour un cercle. */
            pfloat angle1; /* Premier angle, 0 pour un cercle complet. */
            pfloat angle2; /* Second angle, 360 pour un cercle complet. */
            pfloat rotation; /* Angle de rotation global. */
            bool ferme;
    };

    /**
     * @brief PStdVectEllipses2D Vecteur d'ellipses 2D.
     */
    typedef std::vector<Pellipse2D> PStdVectEllipses2D;

    /**
     * @brief Définition d'un texte 2D
     */
    class DLL_API PTexte2D: public PEnt2D
    {
        public:
            PTexte2D();
            PTexte2D(const PTexte2D &t);
            PTexte2D(const char *texte_, const Ppoint2D &position_, pfloat taille_, pfloat rotation_);
            PTexte2D& operator=(const PTexte2D &t);
            ~PTexte2D();

            inline const Ppoint2D &Position() const { return position; }
            inline void defPosition(const Ppoint2D &p) { position.defXY(p.X(), p.Y()); }
            inline void defPositionX(pfloat x) { position.defX(x); }
            inline void defPositionY(pfloat y) { position.defY(y); }

            inline pfloat TailleTexte() const { return taille; }
            inline void defTailleTexte(pfloat t) { taille=t; }

            inline pfloat Rotation() const { return rotation; }
            inline void defRotation(pfloat r) { rotation=r; }

            puint DefTexte(const char *s);

            void Suppr(); /* Supprime le contenu du texte. Libère la mémoire de la chaîne de caractères ! */

            inline const char *Texte() const { return texte; }
            inline puint LongueurTexte() const { return longueur_txt; }

        protected:
            char *texte;
            puint longueur_txt;
            Ppoint2D position;
            pfloat taille;
            pfloat rotation;
    };

    /**
     * @brief PStdVectTextes2D Vecteur de textes 2D.
     */
    typedef std::vector<PTexte2D> PStdVectTextes2D;

    /**
     * @brief PGroupeEnts2D Défini un groupe d'entités 2D.
     */
    class DLL_API PGroupeEnts2D : public PBase
    {
            friend class PGroupeEnts2DPriv;

        public:
            PGroupeEnts2D();
            ~PGroupeEnts2D();

            /**
             * @brief Vide Vide le groupe d'entités.
             */
            void Vide();

            /**
             * @brief Valide Contrôle si le groupe est valide (initialisée et avec des entités) et prêt à être utilisé.
             */
            bool Valide() const;

            /**
             * @brief CompteurEntites Renvoi le nombre total d'entités graphiques (lignes et courbes) dans le groupe.
             */
            pint CompteurEntites() const;

            /**
             * @brief Liste des segments.
             * @return Renvoi la liste des lignes.
             */
            inline const PStdVectLignes2D &ListeLignes() const
            {
                return *listelignes;
            }

            /**
             * @brief Liste des ellipses (ou toutes entitées courbe).
             * @return Renvoi la liste des ellipses.
             */
            inline const PStdVectEllipses2D &ListeEllipses() const
            {
                return *listeellipses;
            }

            /**
             * @brief Liste des textes.
             * @return Renvoi la liste des textes.
             */
            inline const PStdVectTextes2D &ListeTextes() const
            {
                return *listetextes;
            }

            /**
             * @brief Liste dee points.
             * @return Renvoi la liste des points.
             */
            inline const PStdVectPoints2D &ListePoints() const
            {
                return *listepoints;
            }

        protected:
            PStdVectLignes2D *listelignes;
            PStdVectEllipses2D *listeellipses;
            PStdVectTextes2D *listetextes;
            PStdVectPoints2D *listepoints;
    };

    /**
     * @brief PStdVectGroupeEnts2D Vecteur de groupe d'entités 2D.
     */
    typedef std::vector<PGroupeEnts2D *> PStdVectGroupeEnts2D;

    /**
     * @brief Scène 2D
     */
    class DLL_API PScene2D : public PBase
    {
            friend class PScene2DPriv;

        public:
            PScene2D();

            ~PScene2D();

            /**
             * @brief Rempli une scène via l'import d'un fichier DXF. La scène est vidée avant l'import.
             */
            bool ImportDXF(const std::string &fichier, bool ignore_non_imprimable=false, bool nouveau_groupe=false);

#ifdef SUPPORT_VISION2D
            /**
             * @brief Importe une image et tente la conversion en entités vectorielles. La scène n'est pas vidée avant l'import, c'est donc une méthode additive. Pour démarrer une nouvelle scène, elle devra être vidée manuellement.
             */
            resultat_vision2d_t ImportImage(const PImage &img, const ParametresVision &parametres, pfloat origine_x=0.0, pfloat origine_y=0.0, bool nouveau_groupe=false);
#endif // SUPPORT_VISION2D

            /**
             * @brief Export de la scène dans un fichier DXF.
             */
            bool ExportDXF(const std::string &fichier) const;

            /**
             * @brief Avancement Renvoi le pourcentage d'avancement de la génération de la scène (dans le cas d'un import).
             * @return Renvoi un entier entre 0 et 100.
             */
            pint Avancement() const;

            /**
             * @brief Vide Vide la scène
             */
            void Vide();

            /**
             * @brief ValideScene Contrôle si la scène est correctement initialisée et non vide.
             */
            bool ValideScene() const;

            /**
             * @brief AjoutGroupe Ajoute un nouveau groupe d'entités.
             */
            bool AjoutGroupe();

            /**
             * @brief AjoutLigne Ajoute une ligne dans la scène 2D.
             */
            pint AjoutLigne(const Pligne2D &ligne);

            /**
             * @brief AjoutEllipse Ajoute une ellipse (ou toute entité courbe) dans la scène 2D.
             */
            pint AjoutEllipse(const Pellipse2D &ellipse);

            /**
             * @brief AjoutTexte Ajoute un texte dans la scène 2D.
             */
            pint AjoutTexte(const PTexte2D &texte);

            /**
             * @brief AjoutPoint Ajoute un point dans la scène 2D.
             */
            pint AjoutPoint(const Ppoint2D &position);

            /**
             * @brief LiberationImport Libération de la mémoire après un import (optionnel, la libération peut très bien se faire automatiquement à l'appel du destructeur de la scène).
             * Cela permet néanmoins de libérer de la mémoire qui n'est plus utile.
             * @return true si la libération est possible, sinon false.
             */
            bool LiberationImport();

            /**
             * @brief Groupes Renvoi les groupes d'entités de la scène.
             */
            const PStdVectGroupeEnts2D &Groupes() const;

            /**
             * @brief Groupes Renvoi le dernier groupe de la scène (ou un pointeur nul si la scène est vide).
             */
            const PGroupeEnts2D *DernierGroupe() const;

            /**
             * @brief SupprimeDernierGroupe Place le dernier groupe dans la corbeille.
             */
            bool SupprimeDernierGroupe();

            /**
             * @brief RestaureDernierGroupe Restaure le dernier groupe placé dans la corbeille vers la scène.
             */
            bool RestaureDernierGroupe();

            /**
             * @brief CompteurEntites Renvoi le nombre total d'entités graphiques (lignes et courbes) dans la scène.
             */
            pint CompteurEntites() const;

        protected:
            PStdVectGroupeEnts2D *contenu_scene;
            PStdVectGroupeEnts2D *corbeille_scene;

        private:
            int type_import;
            void *ptr_import;
    };

    /* </2D> */

    /* <23D> */
    /**
     * @brief Type de base pour les entitées 2D->3D.
     */
    class DLL_API PEnt23D : public PEntite
    {
        public:
            inline PEnt23D(pident id_, proprietes_3d_t props): PEntite(id_), proprietes(props), couleur() { ; }
            inline PEnt23D(const PCouleur &c, pident id_, proprietes_3d_t props): PEntite(id_), proprietes(props), couleur(c) { ; }
            inline PEnt23D(): PEntite(IDNUL), proprietes(proprietes_3d_t::PROPRIETE_3D_NUL), couleur() { ; }

            inline const PCouleur &CouleurConst() const { return couleur; }
            inline PCouleur &Couleur() { return couleur; }
            inline void defCouleur(const PCouleur &c) { couleur=c; }

            inline void defProprietes(proprietes_3d_t props) { proprietes = props; }
            inline proprietes_3d_t Proprietes() const { return proprietes; }

            inline bool Courbe() const
            {
                return proprietes & proprietes_3d_t::PROPRIETE_3D_COURBE;
            }

            inline void defCourbe(bool etat)
            {
                if (etat != Courbe())
                {
                    proprietes = (etat) ? (proprietes | proprietes_3d_t::PROPRIETE_3D_COURBE) : (proprietes ^ proprietes_3d_t::PROPRIETE_3D_COURBE);
                }
            }

            inline bool Trou() const
            {
                return proprietes & proprietes_3d_t::PROPRIETE_3D_TROU;
            }

            inline void defTrou(bool etat)
            {
                if (etat != Trou())
                {
                    proprietes = (etat) ? (proprietes | proprietes_3d_t::PROPRIETE_3D_TROU) : (proprietes ^ proprietes_3d_t::PROPRIETE_3D_TROU);
                }
            }

        protected:
            proprietes_3d_t proprietes;
            PCouleur couleur;
    };

    /**
     * @brief 3 coordonnées (base pour les points et vecteurs 3D).
     */
    class DLL_API Pvec3 : public PBaseId
    {
        public:
            inline Pvec3(): PBaseId(IDNUL), x(COORD0), y(COORD0), z(COORD0) { ; }
            inline Pvec3(pfloat x_, pfloat y_, pfloat z_) : PBaseId(IDNUL), x(x_), y(y_), z(z_) { ; }
            inline Pvec3(pfloat x_, pfloat y_, pfloat z_, pident id_) : PBaseId(id_), x(x_), y(y_), z(z_) { ; }
            inline Pvec3(const Pvec3 &p1, const Pvec3 &p2) : PBaseId(IDNUL), x(p2.x-p1.x), y(p2.y-p1.y), z(p2.z-p1.z) { ; }

            Pvec3(const Ppoint2D &p1, pfloat z_=0., vues2D_t vue=vues2D_t::VUEFACE);
            Pvec3(const Ppoint2D &f, const Ppoint2D &c, const Ppoint2D &h);

            inline Pvec3(const Pvec3 &p) : PBaseId(p.id), x(p.x), y(p.y), z(p.z) { ; } /* Constructeur de copie. */

            Pvec3& operator=(const Pvec3 &p);

            inline Pvec3 &operator+=(const pfloat s) { x+=s; y+=s; z+=s; return *this; }
            inline Pvec3 &operator-=(const pfloat s) { x-=s; y-=s; z-=s; return *this; }
            inline Pvec3 &operator*=(const pfloat s) { x*=s; y*=s; z*=s; return *this; }
            inline Pvec3 &operator/=(const pfloat s) { x/=s; y/=s; z/=s; return *this; }
            inline Pvec3 &operator*=(const Pvec3 &v) { x*=v.x; y*=v.y; z*=v.z; return *this; }
            inline Pvec3 &operator/=(const Pvec3 &v) { x/=v.x; y/=v.y; z/=v.z; return *this; }
            inline Pvec3 &operator+=(const Pvec3 &v) { x+=v.x; y+=v.y; z+=v.z; return *this; }
            inline Pvec3 &operator-=(const Pvec3 &v) { x-=v.x; y-=v.y; z-=v.z; return *this;}

            inline Pvec3 operator+(const pfloat s) const { return Pvec3(x+s, y+s, z+s); }
            inline Pvec3 operator-(const pfloat s) const { return Pvec3(x-s, y-s, z-s); }
            inline Pvec3 operator*(const pfloat s) const { return Pvec3(x*s, y*s, z*s); }
            inline Pvec3 operator/(const pfloat s) const { return Pvec3(x/s, y/s, z/s); }
            inline Pvec3 operator*(const Pvec3 &v) const { return Pvec3(x*v.x, y*v.y, z*v.z); }
            inline Pvec3 operator/(const Pvec3 &v) const { return Pvec3(x/v.x, y/v.y, z/v.z); }
            inline Pvec3 operator+(const Pvec3 &v) const { return Pvec3(x+v.x, y+v.y, z+v.z); }
            inline Pvec3 operator-(const Pvec3 &v) const { return Pvec3(x-v.x, y-v.y, z-v.z); }

            /**
             * @brief operator != Comparaison entre deux points avec l'Epsilon fixe.
             */
            inline bool operator!=(const Pvec3 &v) const { return !CompareED(x, v.x) || !CompareED(y, v.y) || !CompareED(z, v.z); }

            /**
             * @brief operator == Comparaison entre deux points avec l'Epsilon dynamique.
             */
            inline bool operator==(const Pvec3 &v) const
            {
                return ( CompareED(x, v.x) && CompareED(y, v.y) && CompareED(z, v.z) );
            }

            /**
             * @brief operator < Comparaison entre deux points avec l'Epsilon dynamique.
             */
            inline bool operator<(const Pvec3& v) const
            {
                if (CompareED(x, v.x))
                {
                    if (CompareED(y, v.y))
                    {
                        if (CompareED(z, v.z)) // Egalitée
                            return false;
                        return (z < v.z);
                    }
                    return (y < v.y);
                }
                return (x < v.x);
            }

            /**
             * @brief centre Renvoi le centre entre deux sommets.
             */
            inline Pvec3 centre(const Pvec3 &v) const { return (v + *this) * 0.5; }

            /**
             * @brief cross Produit vectoriel.
             */
            inline Pvec3 cross(const Pvec3 &v) const { return Pvec3((Y()*v.Z()) - (Z()*v.Y()), (Z()*v.X()) - (X()*v.Z()), (X()*v.Y()) - (Y()*v.X())); }

            /**
             * @brief dot Produit scalaire.
             */
            inline pfloat dot(const Pvec3 &v) const { return (X()*v.X()) + (Y()*v.Y()) + (Z()*v.Z()); }

            /**
             * @brief magnitude Distance à l'origine.
             */
            inline pfloat magnitude() const { return RCARREF(POW2(X()) + POW2(Y()) + POW2(Z())); }

            /**
             * @brief Distance2 Distance au carré par rapport à un autre point.
             */
            inline pfloat Distance2(const Pvec3 &p) const { return ( POW2(POSITIFD(x - p.X())) + POW2(POSITIFD(y - p.Y())) + POW2(POSITIFD(z - p.Z())) ); }

            /**
             * @brief Distance Distance par rapport à un autre point.
             */
            inline pfloat Distance (const Pvec3 &p) const { return RCARREF(Distance2(p)); }

            /**
             * @brief lg2 Longueur du vecteur au carré à l'origine.
             */
            inline pfloat lg2() const { return (X()*X()) + (Y()*Y()) + (Z()*Z()); }

            /**
             * @brief lg Longueur du vecteur à l'origine.
             */
            inline pfloat lg() const { return RCARREF(lg2()); }

            /**
             * @brief inv Renvoi une copie du vecteur inversé.
             */
            Pvec3 inv() const;

            /**
             * @brief inv Inverse le vecteur.
             */
            void inv();

            /**
             * @brief inv Normalise le vecteur.
             */
            void normalise();

            /**
             * @brief norme Contrôle si le vecteur est normé à 1
             * @return true si tel est le cas, sinon false.
             */
            bool norme();

            /**
             * @brief echelle Mise à l'échelle par rapport à une origine.
             * @param origine L'origine à partir de laquelle effectuer l'echelle.
             * @param vecteur_echelle Vecteur d'échelle pour chaque axe.
             */
            Pvec3 echelle(const Pvec3 &origine, const Pvec3 &vecteur_echelle);

            /**
             * @brief norm Vecteur normé de l'origine au point courant.
             * @param origine L'origine à partir de laquelle calculer le vecteur.
             */
            Pvec3 norm(const Pvec3 &origine) const;

            /**
             * @brief norm Vecteur de l'origine au point courant.
             * @param origine L'origine à partir de laquelle calculer le vecteur.
             */
            Pvec3 vect(const Pvec3 &origine) const;

            /**
             * @brief Renvoi la coordonée X.
             */
            inline pfloat X() const { return x; }

            /**
             * @brief Assigne la coordonée X.
             */
            inline void defX(pfloat x_) { x=x_; }

            /**
             * @brief Renvoi la coordonée Y.
             */
            inline pfloat Y() const { return y; }

            /**
             * @brief Assigne la coordonée Y.
             */
            inline void defY(pfloat y_) { y=y_; }

            /**
             * @brief Renvoi la coordonée Z.
             */
            inline pfloat Z() const { return z; }

            /**
             * @brief Assigne la coordonée Z.
             */
            inline void defZ(pfloat z_) { z=z_; }

            /**
             * @brief Assigne les coordonnées.
             */
            inline void defCoords(pfloat x_=COORD0, pfloat y_=COORD0, pfloat z_=COORD0) { x=x_; y=y_; z=z_; }

            /**
             * @brief Assigne les coordonnées.
             */
            inline void defCoords(const Pvec3 &p) { x=p.x; y=p.y; z=p.z; }

            /**
             * @brief Assigne les coordonnées partielles (d'après un point 2D et une vue).
             */
            bool defCoords2D(const Ppoint2D &p2d, vues2D_t vue);

            /**
             * @brief Assigne les coordonnées (d'après un point 2D, une vue et la coordonée de profondeur).
             */
            bool defCoords2D(const Ppoint2D &p2d, vues2D_t vue, pfloat z);

            /**
             * @brief Assigne les coordonnées partielles (d'après un point 3D et une vue).
             */
            bool defCoords2D(const Pvec3 &p3d, vues2D_t vue);

            /**
             * @brief Ajout des coordonnées partielles (d'après un point 2D et une vue).
             */
            bool AjoutCoords2D(const Ppoint2D &p2d, vues2D_t vue);

            /**
             * @brief Conversion en point2D suivant une vue.
             */
            Ppoint2D Point2D(vues2D_t vue) const;

            inline bool CoordNul() const { return CompareE(x, COORD0) && CompareE(y, COORD0) && CompareE(z, COORD0); }
            inline bool Nul() const { return id==IDNUL && CoordNul(); }

            inline pfloat at(pint i) const
            {
                return (i==0) ? x : ((i==1) ? y : ((i==2) ? z : -1));
            }

            inline static size_t numDim() { return 3; }

        protected:
            pfloat x, y, z;
    };

    /**
     * @brief Point 3D (base).
     */
    class DLL_API Ppoint3D_min : public PEnt23D
    {
        public:
            inline Ppoint3D_min() : PEnt23D(IDNUL, proprietes_3d_t::PROPRIETE_3D_NUL), vec() { ; }

            inline Ppoint3D_min(const Pvec3 &v): PEnt23D(v.Id(), proprietes_3d_t::PROPRIETE_3D_NUL), vec(v) { ; }

            inline Ppoint3D_min(pfloat x_, pfloat y_, pfloat z_, pident id_=IDNUL): PEnt23D(id_, proprietes_3d_t::PROPRIETE_3D_NUL), vec(x_, y_, z_, id_) { ; }
            inline Ppoint3D_min(pfloat x_, pfloat y_, pfloat z_, const PCouleur &cl, pident id_=IDNUL): PEnt23D(cl, id_, proprietes_3d_t::PROPRIETE_3D_NUL), vec(x_, y_, z_, id_) { ; }

            inline Ppoint3D_min(const Ppoint3D_min &p1, const Ppoint3D_min &p2) : PEnt23D(IDNUL, proprietes_3d_t::PROPRIETE_3D_NUL), vec(p1.vec, p2.vec) { ; }

            inline Ppoint3D_min(const Ppoint3D_min &p) : PEnt23D(p.couleur, p.id, p.proprietes), vec(p.vec) { ; } /* Constructeur de copie. */

            inline Ppoint3D_min& operator=(const Ppoint3D_min &p)
            {
                defId(p.Id());
                defCouleur(p.CouleurConst());
                defProprietes(p.Proprietes());
                vec = p.vec;
                return *this;
            }

            inline void defId(pident id_)
            {
                id = id_;
                vec.defId(id_);
            }

            inline const Pvec3& Vec3() const
            {
                return vec;
            }

            inline Pvec3& Vec3NonConst()
            {
                return vec;
            }

            /**
             * @brief operator != Comparaison entre deux points avec l'Epsilon fixe.
             */
            inline bool operator!=(const Ppoint3D_min &v) const { return vec != v.vec; }

            /**
             * @brief operator == Comparaison entre deux points avec l'Epsilon dynamique.
             */
            inline bool operator==(const Ppoint3D_min &v) const
            {
                return vec == v.vec;;
            }

            /**
             * @brief operator < Comparaison entre deux points avec l'Epsilon dynamique.
             */
            inline bool operator<(const Ppoint3D_min& v) const
            {
                return (vec < v.vec);
            }

            /**
             * @brief Renvoi la coordonée X.
             */
            inline pfloat X() const { return vec.X(); }

            /**
             * @brief Assigne la coordonée X.
             */
            inline void defX(pfloat x_) { vec.defX(x_); }

            /**
             * @brief Renvoi la coordonée Y.
             */
            inline pfloat Y() const { return vec.Y(); }

            /**
             * @brief Assigne la coordonée Y.
             */
            inline void defY(pfloat y_) { vec.defY(y_); }

            /**
             * @brief Renvoi la coordonée Z.
             */
            inline pfloat Z() const { return vec.Z(); }

            /**
             * @brief Assigne la coordonée Z.
             */
            inline void defZ(pfloat z_) { vec.defZ(z_); }

            /**
             * @brief Assigne les coordonnées.
             */
            inline void defCoords(pfloat x_=COORD0, pfloat y_=COORD0, pfloat z_=COORD0) { vec.defCoords(x_, y_, z_); }

            /**
             * @brief Assigne les coordonnées.
             */
            inline void defCoords(const Ppoint3D_min &p) { vec.defCoords(p.vec); }

            /**
             * @brief Distance2 Distance au carré par rapport à un autre point.
             */
            inline pfloat Distance2(const Ppoint3D_min &p) const { return vec.Distance2(p.vec); }

            /**
             * @brief Distance Distance par rapport à un autre point.
             */
            inline pfloat Distance (const Ppoint3D_min &p) const { return vec.Distance(p.vec); }

            inline bool CoordNul() const { return vec.CoordNul(); }

            inline bool Nul() const { return id==IDNUL && CoordNul(); }

            inline pfloat at(pint i) const
            {
                return (vec.at(i));
            }

            inline static size_t numDim() { return 3; }

        protected:
            Pvec3 vec;
    };

    /**
     * @brief Matrice 4x4 basique. Aucun opérateur n'est défini, elle n'est utilisée que pour le transfert des données.
     * <br>
     *\verbatim
             | 0 4  8 12 |
             | 1 5  9 13 |
             | 2 6 10 14 |
             | 3 7 11 15 |
     \endverbatim
     */
    class DLL_API PMat4x4_data : public PBase
    {
        public:
            /**
             * @brief Constructeur (identité)
             */
            inline PMat4x4_data()
            {
                identite();
                data_m[16] = 0;
            }

            /**
             * @brief Constructeur (copie depuis un tampon de nombres flottants).
             */
            inline PMat4x4_data(const pfloat *m)
            {
                def(m);
                data_m[16] = 0;
            }

            /**
             * @brief Constructeur (copie).
             */
            inline PMat4x4_data(const PMat4x4_data &copie)
            {
                def(copie.data());
                data_m[16] = 0;
            }

            /**
             * @brief Constructeur par définition des colonnes.
             */
            inline PMat4x4_data(const Pvec3 &axe_x, const Pvec3 &axe_y, const Pvec3 &axe_z, const Pvec3 &position)
            {
                defAxeX(axe_x);
                defAxeY(axe_y);
                defAxeZ(axe_z);
                defPosition(position);
                data_m[16] = 0;
            }

            /**
             * @brief lookAt : Force la matrice à regarder dans une directions (absolue) depuis un point d'origine (absolue également).
             */
            void lookAt(const Pvec3 &origine_abs, const Pvec3 &destination_abs, const Pvec3 &up);

            void lookAt(const Pvec3 &origine_abs, const Pvec3 &destination_abs);

            /**
             * @brief Assignation du tampon de la matrice.
             */
            inline void def(const pfloat *m)
            {
                data_m[0] = m[0];  data_m[1] = m[1];  data_m[2] = m[2];  data_m[3] = m[3];
                data_m[4] = m[4];  data_m[5] = m[5];  data_m[6] = m[6];  data_m[7] = m[7];
                data_m[8] = m[8];  data_m[9] = m[9];  data_m[10]= m[10]; data_m[11]= m[11];
                data_m[12]= m[12]; data_m[13]= m[13]; data_m[14]= m[14]; data_m[15]= m[15];
            }

            /**
             * @brief Assigne une colonne dans la matrice d'après son index (0 < 4).
             */
            inline void defColonne(puint index, pfloat m1, pfloat m2, pfloat m3, pfloat m4)
            {
                if (index < 4)
                {
                    const puint idt = index * 4;
                    data_m[idt] = m1;  data_m[idt + 1] = m2;  data_m[idt + 2] = m3;  data_m[idt + 3] = m4;
                }
            }

            inline void defAxeX(const Pvec3 &axe)
            {
                defColonne(0, axe.X(), axe.Y(), axe.Z(), 0);
            }

            inline void defAxeY(const Pvec3 &axe)
            {
                defColonne(1, axe.X(), axe.Y(), axe.Z(), 0);
            }

            inline void defAxeZ(const Pvec3 &axe)
            {
                defColonne(2, axe.X(), axe.Y(), axe.Z(), 0);
            }

            inline void defPosition(const Pvec3 &position)
            {
                defColonne(3, position.X(), position.Y(), position.Z(), 1);
            }

            /**
             * @brief Assigne à la matrice l'identité.
             */
            inline void identite()
            {
                data_m[0] = data_m[5] = data_m[10] = data_m[15] = 1.0;
                data_m[1] = data_m[2] = data_m[3] = data_m[4] = data_m[6] = data_m[7] = data_m[8] = data_m[9] = data_m[11] = data_m[12] = data_m[13] = data_m[14] = 0.0;
            }

            /**
             * @brief Renvoi le pointeur vers le tampon de la matrice.
             */
            inline const pfloat *data() const
            {
                return data_m;
            }

            /**
             * @brief Accès à un élément de la matrice (const).
             */
            inline const pfloat& at(puint i) const
            {
                return data_m[i < 16 ? i : 16];
            }

            /**
             * @brief Accès à un élément de la matrice.
             */
            inline pfloat& at(puint i)
            {
                return data_m[i < 16 ? i : 16];
            }

            /**
             * @brief Renvoi le nombre d'éléments dans la matrice.
             */
            static inline puint size()
            {
                return 16;
            }

        private:
            pfloat data_m[17];
    };

    /**
     * @brief PStdVectPoint3D_min Vecteur de points 3D (version légère).
     */
    typedef std::vector<Pvec3> PStdVectPoint3D_min;

    /**
     * @brief Définition d'un point 3D (version lourde, avec quelques propriétés additionnelles).
     */
    class DLL_API Ppoint3D: public Ppoint3D_min
    {
        public:
            inline Ppoint3D(const Pvec3 &p) : Ppoint3D_min(p),
                connexion_lignes(0), id_connexion_courbe(IDNUL) { ; }

            inline Ppoint3D(const Ppoint3D_min &p) : Ppoint3D_min(p),
                connexion_lignes(0), id_connexion_courbe(IDNUL) { ; }

            inline Ppoint3D(const Ppoint3D &p) : Ppoint3D_min(p.X(), p.Y(), p.Z(), p.CouleurConst(), p.Id()),
                connexion_lignes(p.connexion_lignes), id_connexion_courbe(p.id_connexion_courbe)
            {
                defProprietes(p.Proprietes());
            }

            inline Ppoint3D(): connexion_lignes(0), id_connexion_courbe(IDNUL) { ; }

            inline Ppoint3D(pfloat x_, pfloat y_, pfloat z_, pident id_=IDNUL, bool ellipse_=false): Ppoint3D_min(x_, y_, z_, id_),
                connexion_lignes(0), id_connexion_courbe(IDNUL)
            {
                defCourbe(ellipse_);
            }

            inline Ppoint3D& operator=(const Ppoint3D &p)
            {
                defId(p.Id()); defCouleur(p.CouleurConst()); defCoords(p.X(), p.Y(), p.Z());
                defProprietes(p.Proprietes());
                connexion_lignes = p.connexion_lignes; id_connexion_courbe=p.id_connexion_courbe;
                return *this;
            }

            inline void defId(pident id_)
            {
                id = id_;
                vec.defId(id_);
            }

            inline pident IdConnexionCourbe() const { return id_connexion_courbe; }
            inline void defIdConnexionCourbe(pident id) { id_connexion_courbe=id; }

            inline puint ConnexionLignes() const { return connexion_lignes; }
            inline void IncConnexionLignes() { ++connexion_lignes; }

        protected:
            puint connexion_lignes;
            pident id_connexion_courbe;
    };

    /**
     * @brief PStdVectPoint3D Vecteur pour les points 3D (version lourde).
     */
    typedef std::vector<Ppoint3D> PStdVectPoint3D;

    /**
     * @brief Lignes 3D.
     */
    class DLL_API Pligne3D: public PEnt23D
    {
        public:
            inline Pligne3D(): PEnt23D(), norml(), jointure_trou(false) { ; }

            inline Pligne3D(const Pligne3D &l) : PEnt23D(l.CouleurConst(), l.Id(), l.Proprietes()),
                p1p(l.p1p), p2p(l.p2p), norml(l.norml), jointure_trou(l.jointure_trou)
            {
                ;
            }

            inline Pligne3D(const Ppoint3D &p1_, const Ppoint3D &p2_, pident id_=IDNUL, bool ellipse_=false): PEnt23D(),
                p1p(p1_), p2p(p2_), norml(Pvec3()), jointure_trou(false)
            {
                defId(id_); defCourbe(ellipse_);
            }

            inline Pligne3D& operator=(const Pligne3D &l)
            {
                defProprietes(l.Proprietes());
                defId(l.Id()); defCouleur(l.CouleurConst());
                p1p = l.p1p; p2p = l.p2p; norml = l.norml; jointure_trou = l.jointure_trou;
                return *this;
            }

            inline const Ppoint3D &P1Const() const { return p1p; }
            inline const Ppoint3D &P2Const() const { return p2p; }

            inline const Pvec3 &V1Const() const { return p1p.Vec3(); }
            inline const Pvec3 &V2Const() const { return p2p.Vec3(); }

            inline Ppoint3D &P1() { return p1p; }
            inline Ppoint3D &P2() { return p2p; }
            inline void defP1(const Ppoint3D &p) { p1p=p; defId(IDNUL); } /* Si on change un point, l'id n'est plus fiable. */
            inline void defP2(const Ppoint3D &p) { p2p=p; defId(IDNUL); }

            inline void defPoints(const Ppoint3D &p1, const Ppoint3D &p2) { p1p=p1; p2p=p2; defId(IDNUL); }

            inline void defCourbe(bool e)
            {
                PEnt23D::defCourbe(e);
                p1p.defCourbe(e); p2p.defCourbe(e);
            }

            inline bool ConnexionTrou() const { return Trou(); }
            inline void defConnexionTrou(bool c) { defTrou(c); }

            inline bool JointureTrou() const { return jointure_trou; }
            inline void defJointureTrou(bool c) { jointure_trou = c; }

            const Pvec3 &NormL() const { return norml; }
            void defNormL(const Pvec3 &n) { norml=n; }

            inline pfloat Longueur2() const { return p1p.Distance2(p2p); } /* Longueur de la ligne au carré */
            inline pfloat Longueur() const { return p1p.Distance(p2p); } /* Longueur de la ligne. */

            inline bool Nulle() const { return (p1p == p2p); }

            /**
             * @brief operator == Comparaison entre deux lignes avec l'Epsilon dynamique.
             */
            inline bool operator==(const Pligne3D &l) const
            {
                return ( ((p1p == l.p1p) && (p2p == l.p2p)) || ((p1p == l.p2p) && (p2p == l.p1p)) );
            }

            /**
             * @brief operator < Comparaison entre deux lignes avec l'Epsilon dynamique.
             */
            inline bool operator<(const Pligne3D& l) const
            {
                if (p1p < p2p)
                { return ( (p1p < l.p1p) && (p1p < l.p2p) ); }
                return ( (p2p < l.p1p) && (p2p < l.p2p) );
            }

        protected:
            Ppoint3D p1p;
            Ppoint3D p2p;
            Pvec3 norml;
            bool jointure_trou;
    };

    /**
     * @brief PStdVectLigne3D Vecteur de lignes 3D.
     */
    typedef std::vector<Pligne3D> PStdVectLigne3D;

    /* </23D> */

    /* <3D> */
    /**
     * @brief Type de base pour les entitées strictement 3D.
     */
    class DLL_API PEnt3D: public PEnt23D
    {
        public:
            inline PEnt3D(): PEnt23D(IDNUL, proprietes_3d_t::PROPRIETE_3D_NUL), actif(true) { ; }
            inline PEnt3D(const PCouleur &c, pident i, bool a) : PEnt23D(c, i, proprietes_3d_t::PROPRIETE_3D_NUL), actif(a) { ; }

            inline bool Actif() const { return actif; }
            inline void defActif(bool a) { actif=a; }

        protected:
            bool actif;
    };

    /**
     * @brief Type de base pour les entitées strictement 3D (version étendue avec vecteur normal).
     */
    class DLL_API PEnt3DExt: public PEnt3D
    {
        public:
            inline PEnt3DExt(): PEnt3D(), norm() { ; }
            inline PEnt3DExt(const PCouleur &c, pident i, const Pvec3 &n, bool a) : PEnt3D(c, i, a), norm(n) { ; }

            inline const Pvec3 &Norm() const { return norm; }
            inline Pvec3 &NormNonConst() { return norm; }

            inline void defNorm(const Pvec3 &n) { norm=n; }
            inline void defNorm(pfloat x, pfloat y, pfloat z) { norm.defCoords(x, y, z); }

        protected:
            Pvec3 norm;
    };

    /**
     * @brief Définition d'un segment de droite à base de vertices (destiné à l'affichage 3D).
     */
    class DLL_API PSegment3D : public PEnt3D
    {
            friend class PSegment3DPriv;

        public:
            inline PSegment3D(): PEnt3D(), v1(), v2(), courbe(false) { ; }
            PSegment3D(const PSegment3D &tr);
            PSegment3D(const Pvec3 &p1, const Pvec3 &p2, PCouleur const &couleur_=PCouleur(), bool courbe_=false, pident id_=IDNUL);
            PSegment3D& operator=(const PSegment3D &tr);

            inline bool Courbe() const
            {
                return courbe;
            }

            /**
             * @brief V1 Accès au premier sommet du segment.
             */
            inline const Pvec3 &V1() const { return v1; }

            /**
             * @brief V2 Accès au premier sommet du segment.
             */
            inline const Pvec3 &V2() const { return v2; }

        protected:
            Pvec3 v1;
            Pvec3 v2;
            bool courbe;
    };

    /**
     * @brief PStdVectSegments3D Vecteur de segments.
     */
    typedef std::vector<PSegment3D> PStdVectSegments3D;

    /**
     * @brief Définition d'un sommet (destiné à l'affichage 3D).
     */
    class DLL_API PSommet3D : public PEnt3DExt
    {
            friend class PSommet3DPriv;

        public:
            inline PSommet3D() : PEnt3DExt(), v1() { ; }

            PSommet3D(const PSommet3D &tr);

            PSommet3D(const Pvec3 &p1, const Pvec3 &norm=Pvec3(0,0,0), PCouleur const &couleur_=PCouleur());

            PSommet3D& operator=(const PSommet3D &tr);

            void defId(pident id_);

            /**
             * @brief V1 Accès au Sommet
             */
            inline const Pvec3 &V1() const { return v1; }

        protected:
            Pvec3 v1;
    };

    /**
     * @brief PStdVectSommets3D Vecteur de sommets.
     */
    typedef std::vector<PSommet3D> PStdVectSommets3D;

    /**
     * @brief Définition d'un triangle à base de vertices (destiné à l'affichage 3D).
     */
    class DLL_API Ptriangle3D : public PEnt3DExt
    {
            friend class Ptriangle3DPriv;

        public:
            inline Ptriangle3D(): PEnt3DExt(), v1(), v2(), v3() { ; }

            Ptriangle3D(const Ptriangle3D &tr);

            Ptriangle3D(const Pvec3 &p1, const Pvec3 &p2, const Pvec3 &p3, const Pvec3 norm_=Pvec3(), PCouleur const &couleur_=PCouleur(), pident id_=IDNUL);

            Ptriangle3D& operator=(const Ptriangle3D &tr);

            /**
             * @brief V1 Accès au premier sommet du triangle.
             */
            inline const Pvec3 &V1() const { return v1; }

            /**
             * @brief V2 Accès au premier sommet du triangle.
             */
            inline const Pvec3 &V2() const { return v2; }

            /**
             * @brief V3 Accès au premier sommet du triangle.
             */
            inline const Pvec3 &V3() const { return v3; }

        protected:
            Pvec3 v1;
            Pvec3 v2;
            Pvec3 v3;
    };

    /**
     * @brief PStdVectTriangles3D Vecteur de triangles.
     */
    typedef std::vector<Ptriangle3D> PStdVectTriangles3D;

    /**
     * @brief Définition d'un cube 3D orthogonal aux axes X, Y et Z.
     * <br>
     *\verbatim
         8-------7
        /|      /|
       / |     / |
      4--|----3  |
      |  5----|--6
      | /     | /
      1-------2
     \endverbatim
     */
    class DLL_API PCube3D : public PBase
    {
        public:
            /**
             * @brief PCube3D Créé un cube vide.
             */
            PCube3D();

            /**
             * @brief PCube3D créé un cube avec les bornes données en arguments (les deux sommets de la diagonale du cube).
             */
            PCube3D(const Pvec3 &p_min, const Pvec3 p_max);

            /**
             * @brief PCube3D Constructeur de copie.
             */
            PCube3D(const PCube3D &c);

            /**
             * @brief ReinitEnglobage Réinitialise le delta du cube pour initialiser un nouvel englobage.
             */
            void ReinitEnglobage();

            /**
             * @brief ValideEnglobage Contrôle si l'englobage est valide (le delta n'est plus sur la position d'initialisation).
             */
            bool ValideEnglobage() const;

            /**
             * @brief EnglobeSommet Adapte le delta du cube pour inclure le sommet donné en argument.
             */
            void EnglobeSommet(const Pvec3 &p);

            /**
             * @brief EnglobeSommet Adapte le delta du cube pour inclure le sommet donné en argument.
             */
            inline void EnglobeSommet(const Ppoint3D_min &p)
            {
                EnglobeSommet(p.Vec3());
            }

            /**
             * @brief ContientSommet Contrôle si le sommet donné en argument est à l'intérieur du cube.
             */
            bool ContientSommet(const Pvec3 &p) const;

            /**
             * @brief ContientSommet Contrôle si le sommet donné en argument est à l'intérieur du cube.
             */
            inline bool ContientSommet(const Ppoint3D_min &p) const
            {
                return ContientSommet(p.Vec3());
            }

            /**
             * @brief ContientSommet Contrôle si le sommet donné en argument est à l'intérieur du cube.
             */
            bool ContientSommet(pfloat x, pfloat y, pfloat z) const;

            /**
             * @brief Collision Contrôle de collision entre deux cubes.
             */
            bool Collision(const PCube3D &c) const;

            /**
             * @brief Collision Contrôle de collision entre deux cubes (avec tolérance).
             */
            bool Collision2(const PCube3D &c) const;

            /**
             * @brief Decalage Déplace le cube.
             */
            void Decalage(const Pvec3 &d);

            /**
             * @brief Echelle Mise à l'echelle du cube.
             */
            void Echelle(pfloat e);

            /**
             * @brief Recupère les sommets du cube selon leur id:
             */

            inline Pvec3 P1() const { return v_min; }
            inline Pvec3 P2() const { return Pvec3(v_max.X(), v_min.Y(), v_min.Z()); }
            inline Pvec3 P3() const { return Pvec3(v_max.X(), v_max.Y(), v_min.Z()); }
            inline Pvec3 P4() const { return Pvec3(v_min.X(), v_max.Y(), v_min.Z()); }

            inline Pvec3 P5() const { return Pvec3(v_min.X(), v_min.Y(), v_max.Z()); }
            inline Pvec3 P6() const { return Pvec3(v_max.X(), v_min.Y(), v_max.Z()); }
            inline Pvec3 P7() const { return v_max; }
            inline Pvec3 P8() const { return Pvec3(v_min.X(), v_max.Y(), v_max.Z()); }

            inline Pvec3 Centre() const { return (v_min+v_max)*.5; }

            inline const Pvec3 &PMin() const { return v_min; }
            inline const Pvec3 &PMax() const { return v_max; }

            pfloat CoordMin() const;
            pfloat CoordMax() const;
            pfloat LDiagonale() const;

            void Dilate(pfloat x, pfloat y, pfloat z);
            void Dilate(pfloat xyz);

        protected:
            Pvec3 v_min, v_max;
    };

    /**
     * @brief Définition d'un texte 3D divisé en vertices.
     */
    class DLL_API PTexte3D : public PEnt3D
    {
            friend class PTexte3DPriv;

        public:
            PTexte3D();

            explicit PTexte3D(const PTexte3D &txt);

            PTexte3D(const wchar_t *s, puint nb_chars, pfloat pos_x, pfloat pos_y, pfloat pos_z, const PCouleur &couleur, const pfloat taille, bool centrer=false);

            const PStdVectSegments3D &Vertices() const
            {
                return vertices;
            }

            /**
             * @brief CollisionTextes Contrôle si deux textes 3D entrent en collision.
             */
            bool CollisionTextes(const PTexte3D &txt) const;

            const Pvec3 &Origine() const { return origine; }

        protected:
//            Pvec3 v_min, v_max;
            Pvec3 origine;
            PCube3D cube_texte;
            PStdVectSegments3D vertices;
    };

    /**
     * @brief PStdVectTexte3D Vecteur de textes 3D.
     */
    typedef std::vector<PTexte3D> PStdVectTexte3D;

    /**
     * @brief Défini une surface 3D à partir d'un ensemble de sous-lignes représentant son contour
     */
    class DLL_API PSurface3D : public PEnt3DExt
    {
            friend class PSurface3DPriv;

        public:
            inline PSurface3D() : contour(nullptr), triangles(nullptr), centre(), rayon(0) { ; }
//            ~PSurface3D();

            void Alloc();
            void Dealloc();
            bool ValideAllocaction() const;

            void Copie(const PSurface3D &source);
            PSurface3D& operator=(const PSurface3D &s);

            void defId(pident id_);

            inline const PStdVectSegments3D &ContourConst() const { return *contour; }
            inline const PStdVectTriangles3D &TrianglesConst() const { return *triangles; }

            puint NTriangles() const;
            puint NSommets() const;

            void defTrianglesActif(bool etat);

            inline const Pvec3 &Centre() const { return centre; }
            inline pfloat Rayon() const { return rayon; }

        private:
            PStdVectSegments3D *contour;        /* Lignes correspondantes au contour de la surface. */
            PStdVectTriangles3D *triangles;     /* Triangles de la surface (après triangulation). */
            Pvec3 centre;                       /* Centre de la surface. */
            pfloat rayon;                       /* Rayon de la surface (delta maximum depuis le centre) pour le traitement des collisions. */
    };

    /**
     * @brief PStdVectSurfaces3D Vecteur de surfaces.
     */
    typedef std::vector<PSurface3D> PStdVectSurfaces3D;

    /**
     * @brief PStdSolide3D contient un ensemble de surfaces (d'après leur ids)
     */
    typedef std::vector<pident> PStdSolide3D;

    /**
     * @brief Défini un solide (d'après un ensemble d'identifiants de surfaces 3D).
     */
    class DLL_API PSolide3D : public PEnt3D
    {
            friend class PSolide3DPriv;

        public:
            PSolide3D();

            inline const PStdSolide3D &Surfaces() const { return solide; }

            inline pint NombreSurfaces() const { return solide.size(); }

            inline pident IdSurface(puint i) const
            {
                if (i < solide.size()) { return solide[i]; }
                return IDNUL;
            }

        private:
            PStdSolide3D solide;
    };

    /**
     * @brief PStdVectSolide3D Vecteur de solides.
     */
    typedef std::vector<PSolide3D> PStdVectSolide3D;

    /**
     * @brief Définition d'un maillage 3D
     */
    class DLL_API Pmaillage3D : public PBase
    {
            friend class Pmaillage3DPriv;
            friend class PScene3D;

        public:
            Pmaillage3D();

            ~Pmaillage3D();

            /**
             * @brief Constructeur de copie (avec Mutex, l'ajout d'éléments dans le maillage d'origine est bloqué pendant la copie).
             * @param mesh Le maillage à copier.
             */
            Pmaillage3D(const Pmaillage3D &mesh);

            /**
             * @brief Vide le maillage.
             */
            void Vide();

            /**
             * @brief Importe un maillage.
             * @return Renvoi true si tout s'est bien passé, sinon false.
             */
            bool ImporteMaillage(const Pmaillage3D &mesh, const PMat4x4_data &mat_data=PMat4x4_data());

            /**
             * @brief Import un maillage depuis un fichier STL.
             */
            bool ImportSTL(const char *chemin, puint id_couleur_ral=9010, bool fusion_triangles=false, bool *interrupteur=nullptr, pulong *avancement=nullptr, pfloat *echelle_tmp=nullptr);

            /**
             * @brief Conversion du maillage 3D en une scène 2D.
             */
            bool ConversionScene2D(PScene2D &scene2d, const PMat4x4_data matrice=PMat4x4_data(), const PCouleur &couleur=PCouleur(180, 180, 180, true)) const;

            /**
             * @brief Applique une transformation matricielle à l'ensemble du maillage.
             */
            bool Transform(const PMat4x4_data &mat_data);

            /**
             * @brief Assigne les dimensions du maillage dans les variables données en argument (autrement dit, on calcule le volume du maillage).
             */
            bool AssigneDimensions(pfloat &x, pfloat &y, pfloat &z) const;

            /**
             * @brief FilaireConst Renvoi les vertices du modèle filaire.
             */
            inline const PStdVectSegments3D &Filaire() const { return *filaire; }

            /**
             * @brief SommetsConst Renvoi les sommets du modèle.
             */
            inline const PStdVectSommets3D &Sommets() const { return *sommets; }

            /**
             * @brief SurfacesConst Renvoi les surfaces du modèle.
             */
            inline const PStdVectSurfaces3D &Surfaces() const { return *surfaces; }

            /**
             * @brief GenereArbresRecherche (Optionnel) Genère les arbres de recherche pour les sommets et les surfaces.
             * Permet d'optimiser la vitesse de recherche des sommets voisins.
             * Si les arbres n'ont pas été générés, un algorithme linéaire sera appliqué dans les fonctions de recherche.
             */
            bool GenereArbresRecherche();

            /**
             * @brief SommetProche Renvoi l'identifiant du sommet le plus proche du sommet donné en argument.
             * @return Renvoi IDNUL si aucune reponse satisfaisante n'a été trouvée.
             */
            pident SommetProche(const Pvec3 &p, pfloat *distance2=nullptr) const;

            /**
             * @brief SurfaceProche Renvoi l'identifiant du segment le plus proche du sommet donné en argument.
             * @return Renvoi IDNUL si aucune reponse satisfaisante n'a été trouvée.
             */
            pident SegmentProche(const Pvec3 &p, pfloat *distance2=nullptr) const;

            /**
             * @brief SurfaceProche Renvoi l'identifiant de la surface la plus proche du sommet donné en argument.
             * @return Renvoi IDNUL si aucune reponse satisfaisante n'a été trouvée.
             */
            pident SurfaceProche(const Pvec3 &p, pfloat *distance2=nullptr) const;

        private:
            PStdVectSegments3D *filaire;    /* Modèle filaire */
            PStdVectSommets3D *sommets;     /* Sommets (points) des vertices) */
            PStdVectSurfaces3D *surfaces;   /* Vecteur de surfaces, chacun des élément contient un nombre indéterminé de points représentant une surface. */
            void *arbre_sommets;
            void *arbre_filaire;
            void *arbre_surfaces;
    };

    /**
     * @brief Scène3D, contient l'ensemble des éléments générés.
     */
    class DLL_API PScene3D : public PBase
    {
            friend class PScene3DPriv;

        public:
            PScene3D();

            /**
             * @brief PScene3D Constructeur de copie.
             * @param scene La scène à copier.
             */
            PScene3D(const PScene3D &scene);

            ~PScene3D();

            /**
             * @brief Vide la scène.
             */
            void Vide();

            /**
             * @brief Importe une scène 3D.
             * @return Renvoi true si tout s'est bien passé, sinon false.
             */
            bool ImporteScene3D(const PScene3D &scene, const PMat4x4_data &mat_data=PMat4x4_data());

            /**
             * @brief Importe un fichier STL dans la scène.
             */
            bool ImportSTL(const char *chemin, puint id_couleur_ral, bool fusion_triangles=false, bool *interrupteur=nullptr, pulong *avancement=nullptr);

            /**
             * @brief Applique une transformation matricielle à l'ensemble de la scène.
             */
            bool Transform(const PMat4x4_data &mat_data);

            /**
             * @brief Génère une vignette de la scène.
             */
            PImage GenerationVignette(puint taille_vignette=128, vues2D_t vue=vues2D_t::VUEMULT) const;

            /**
             * @brief Verrouille la scène (on empêche l'ajout de nouveaux éléments). Sans effet si Perspective3D est compilé sans le support du multithreading.
             */
            void Verrouille() const;

            /**
             * @brief DeVerrouille la scène. Sans effet si Perspective3D est compilé sans le support du multithreading.
             */
            void DeVerrouille() const;

            /**
             * @brief Genère les arbres de recherche pour le maillage 3D. Voir Pmaillage3D::GenereArbresRecherche()
             */
            bool GenereArbresRecherche();

            /**
             * @brief Export générique avec assignation automatique du type de fichier en fonction du nom du fichier.
             * @return Renvoi false si le type de fichier n'est pas reconnu ou que l'export a échoué.
             */
            bool Export(const char *nom_fichier) const;

            /**
             * @brief Export DXF.
             * @param nom_fichier le nom du fichier
             * @param parametres_export Paramètres d'export (voir l'enum ::params_export_dxf_t).
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportDXF(const char *nom_fichier, params_export_dxf_t parametres_export=params_export_dxf_t::EXPORT_DXF_SOLIDE_MESH|params_export_dxf_t::EXPORT_DXF_SOLIDE_MESH_GROUPE) const;

            /**
             * @brief Export STL (Stéréolithographie)
             * @param nom_fichier Le nom du fichier.
             * @param separe_solides Si l'on doit enregistrer dans des fichiers à part pour chacun des solides.
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportSTL(const char *nom_fichier, bool separe_solides=false) const;

            /**
             * @brief Export AMF (Additive Manufacturing File)
             * @param nom_fichier Le nom du fichier.
             * @param compression Défini si le fichier doit être compressé (sous forme d'archive ZIP tel que défini dans la norme).
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportAMF(const char *nom_fichier, bool compression=true) const;

            /**
             * @brief Export 3DS (3Ds Max)
             * @param nom_fichier Le nom du fichier.
             * @return true si tout se passe bien, sinon false.
             */
            bool Export3DS(const char *nom_fichier) const;

            /**
             * @brief Export Collada (.dae)
             * @param nom_fichier Le nom du fichier.
             * @param export_couleur_solides Doit on inclure la couleur des solides ?
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportCollada(const char *nom_fichier, bool export_couleur_solides=false) const;

            /**
             * @brief Export PLY (Stanford Triangle Format)
             * @param nom_fichier Le nom du fichier.
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportPLY(const char *nom_fichier) const;

            /**
             * @brief Export OBJ (Wavefront Object)
             * @param nom_fichier Le nom du fichier.
             * @param groupe_solides Groupe (ou non) les solides dans le même objet.
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportOBJ(const char *nom_fichier, bool groupe_solides=false) const;

            /**
             * @brief Export X3D
             * @param nom_fichier Le nom du fichier.
             * @return true si tout se passe bien, sinon false.
             */
            bool ExportX3D(const char *nom_fichier) const;

            /**
             * @brief Maillage Renvoi le modèle à afficher.
             */
            inline const Pmaillage3D &Maillage() const { return *mesh; }

            /**
             * @brief Projections Renvoi le modèle des projections.
             */
            inline const PStdVectSegments3D &Projections() const { return *projections; }

            /**
             * @brief Developpe Renvoi le modèle des développés (cas particulier, en principe pour afficher uniquement de la 2D dans la vue 3D).
             */
            inline PStdVectTriangles3D &Developpe() const { return *developpe; }

            /**
             * @brief Divers Renvoi le modèle divers.
             */
            inline const PStdVectTriangles3D &Divers() const { return *divers; }

            /**
             * @brief Solides Renvoi la liste des solides.
             */
            inline const PStdVectSolide3D &Solides() const { return *solides; }

            /**
             * @brief Textes3D Renvoi la liste des textes 3D.
             */
            inline const PStdVectTexte3D &Textes3D() const { return *textes; }

            /**
             * @brief Renvoi un sommet particulier du maillage.
             */
            PSommet3D &Sommet(puint id) const;

            /**
             * @brief Renvoi un segment particulier du maillage.
             */
            PSegment3D &Segment(puint id) const;

            /**
             * @brief Renvoi une surface particulière du maillage.
             */
            PSurface3D &Surface(puint id) const;

            /**
             * @brief Renvoi un solide particulier du maillage.
             */
            PSolide3D &Solide(puint id) const;

            /**
             * @brief Renvoi un texte particulièr de la scène.
             */
            PTexte3D &Texte(puint id) const;

            /**
             * @brief Couleur Renvoi la couleur de préférence pour afficher la scène.
             */
            inline puint CouleurRAL() const { return id_ral; }

            /**
             * @brief Centre Renvoi le centre de la scène.
             */
            inline const Pvec3 &Centre() const { return centre; }

            /**
             * @brief TempsGeneration Renvoi le tremps de génération (en millisecondes).
             */
            inline pulong TempsGeneration() const { return temps_generation; }

            /**
             * @brief DimX Renvoi la taille de la scène en X.
             */
            inline pfloat DimX() const { return dimx; }

            /**
             * @brief DimY Renvoi la taille de la scène en Y (en principe l'utilisateur n'a pas à y toucher, Perspective s'en chargera).
             */
            inline pfloat DimY() const { return dimy; }

            /**
             * @brief DimZ Renvoi la taille de la scène en Z.
             */
            inline pfloat DimZ() const { return dimz; }

            /**
             * @brief Echelle Renvoi l'echelle à appliquer sur le solide pour le rendre normé à 1.
             */
            inline pfloat Echelle() const { return echelle; }


            inline pfloat EchelleDeveloppe() const { return echelle_developpe; }

            /**
             * @brief NbSurfaces Renvoi le nombre de surfaces dans la scène.
             */
            inline puint NbSurfaces() const { return mesh->Surfaces().size(); }

        private:
            Pmaillage3D *mesh;
            PStdVectSegments3D *projections;    /* Modèle filaire des entités à l'origine 2D projetés autour du modèle. */
            PStdVectTriangles3D *developpe;     /* Modèle développé (strictement 2D en principe) */
            PStdVectTriangles3D *divers;        /* Modèle divers, affiche toutes informations autre que celles ci-dessus. */
            PStdVectSolide3D *solides;          /* Ensemble des solides. */
            PStdVectTexte3D *textes;            /* Vecteurs des textes 3D. */
            Pvec3 centre;                       /* Décalages à appliquer pour placer l'objet 3D au centre de la scène. */
            pulong temps_generation;            /* Temps écoulé pour la génération du mesh. */
            pfloat echelle;                     /* Echelle à appliquer pour voir le modèle entier avec une taille maximum de 1. */
            pfloat echelle_developpe;           /* Echelle d'affichage spécifique pour le développé. */
            puint id_ral;
            pfloat dimx;
            pfloat dimy;
            pfloat dimz;
    };

    /* </3D> */

} // namespace Perspective3D

#endif // PERSPECTIVE_TYPES_H
