Ejemplo n.º 1
0
        //cette fonction convertie une coordonné virtuel en sa position dans l'image, et sa position virtuel relative à la caméra, en prenant également en considération l'angle verticale actuel de la caméra.
        private p3d2d convVirtualToUI(double x, double y, double z, int imgWidth, int imgHeight, double coss, double sinn)
        {
            double MulFactor = (double)imgHeight / 2d / this.ViewAngle;             //il suffit de multiplier un angle/rapport par cette valeur pour connaitre en pixel la distance graphique qu'il représente à l'image

            //il faut effectuer une rotation sur l'axe x, dans la direction de z+ vers y+, et d'un angle de rotation étant this.camAngle.
            //la multiplication complexe est utilisé pour effectuer cette rotation.
            //double zz = (z * coss) - (y * sinn);
            //double yy = (z * sinn) + (y * coss);
            double[] rotated = this.RotateOnX(y, z, coss, sinn);
            double   zz      = rotated[0];
            double   yy      = rotated[1];

            double dist   = this.camZ - zz;           //il faut calculer la distance z (z relatif à la caméra) entre le point et la caméra, qui a changé à cause de la rotation sur l'axe x
            double deltaX = x - this.camX;
            double deltaY = yy;

            p3d2d rep = new p3d2d(0, 0);

            rep.uix = (int)(((double)imgWidth / 2d) + (deltaX / dist * MulFactor) + 0.5d);             //+0.5d pour l'arrondir correctement
            rep.uiy = (int)(((double)imgHeight / 2d) - (deltaY / dist * MulFactor) + 0.5d);
            rep.x   = deltaX;
            rep.y   = yy;
            rep.z   = zz;

            return(rep);
        }
Ejemplo n.º 2
0
        public void Refresh()
        {
            int imgWidth  = this.Width;
            int imgHeight = this.Height;

            if (imgWidth < 100)
            {
                imgWidth = 100;
            }
            if (imgHeight < 100)
            {
                imgHeight = 100;
            }
            Bitmap   img = new Bitmap(imgWidth, imgHeight);
            Graphics g   = Graphics.FromImage(img);

            g.Clear(Color.White);

            double MulFactor = (double)imgHeight / 2d / this.ViewAngle;

            //ces 2 valeurs sont utilisées pour effectuer une rotation des coordonnés sur le cylindre
            double coss = Math.Cos(this.camAngle);
            double sinn = Math.Sin(this.camAngle);


            ////dessine le cylindre
            int uicTopSpace = (int)((this.ViewAngle - (1d / this.camZ)) * MulFactor); //espacement verticale entre le cylindre et les bords de l'image en haut et en bas
            int uicHeight   = imgHeight - uicTopSpace - uicTopSpace;                  //hauteur graphique du cylindre

            //position graphique de la gauche du cylindre
            int uicLeft = (imgWidth / 2) - (int)((this.CylinderBorderWidth + this.camX) / this.camZ * MulFactor);

            if (uicLeft < 0)
            {
                uicLeft = 0;
            }

            //position graphique de la droite du cylindre
            int uicRight = (imgWidth / 2) + (int)((this.VirtualRightEnd - this.camX) / this.camZ * MulFactor);

            //dessine le corps principale du cylindre
            g.FillRectangle(this.CylinderBrush, uicLeft, uicTopSpace, uicRight - uicLeft, uicHeight);
            //dessine le bord gauche s'il le faut
            if (uicLeft > 0)
            {
                //calcule la position graphique du bord gauche, mais la position du cercle qui est la plus proche de la caméra
                int uicCloseLeft = (imgWidth / 2) - (int)((this.CylinderBorderWidth + this.camX) / (this.camZ - 1d) * MulFactor);
                g.FillEllipse(this.CylinderBrush, uicCloseLeft, uicTopSpace, 2 * (uicLeft - uicCloseLeft), uicHeight);
            }
            //dessine le bord droit s'il le faut
            if (uicRight < imgWidth)
            {
                //calcule la position graphique du bord droit, mais la position du cercle qui est la plus proche de la caméra
                int uicCloseRight = (imgWidth / 2) + (int)((this.VirtualRightEnd - this.camX) / (this.camZ - 1d) * MulFactor);
                g.FillEllipse(this.CylinderBrush, 2 * uicRight - uicCloseRight, uicTopSpace, 2 * (uicCloseRight - uicRight), uicHeight);
            }



            //si l'élément actuellement sélectionné est dans l'image (ca devrait être presque toujours le cas), cette variable sera true et le p3d2d sera gardé dans l'autre variable
            bool      SelectedElemFound = false;        //devient true si l'élément actuel est dans l'image
            clElement SelectedElem      = null;
            p3d2d     SelectedPos       = new p3d2d(0, 0);

            double minimumZ = this.ViewAngle;             // coordonné z+ minimum pour qu'un point de la surface du cylindre soit sur la face visible par la caméra

            ////dessine les élément
            int index = 0;

            while (index < this.listElem.Count)
            {
                clElement elem = this.listElem[index];

                //on doit d'abord obtenir ses coordonnés réel.
                double elemX = elem.x;
                double elemY = -Math.Sin(elem.angle);
                double elemZ = Math.Cos(elem.angle);

                //maintenant on obtien ses coordonnés relatives à la caméra
                p3d2d  relpos = this.convVirtualToUI(elemX, elemY, elemZ, imgWidth, imgHeight, coss, sinn);
                double dist   = this.camZ - relpos.z;

                //check s'il sort de l'écran. si c'est le cas, on peut arrêter car tout les suivant seront eux aussi dehors de l'image
                if (relpos.uix > imgWidth)
                {
                    break;
                }

                //check si l'item est actuellement visible à l'écran en vérifiant si le côté droit du texte est dans l'image
                int uiWidth = (int)(elem.VirtualTextWidth / dist * MulFactor);
                if (relpos.uix + uiWidth >= 0)
                {
                    //si on est sur l'élément sélectionné par l'user, on le garde de côté
                    if (index == this.SelectedIndex)
                    {
                        SelectedElemFound = true;
                        SelectedElem      = elem;
                        SelectedPos       = relpos;
                    }

                    //on check si l'élément est du côté visible du cylindre
                    if (relpos.z > minimumZ)
                    {
                        //on calcul l'applatissement verticale du text.
                        float TextYScale = (float)(relpos.z);

                        //on calcule le height que la font doit avoir
                        Font elemFont = new Font(this.uiFontName, (float)((double)imgHeight * this.uiCloseFontMulFactor * (this.camZ - 1d) / dist));
                        //on calcule la taille graphique qu'aura le text
                        SizeF elemTextSize = g.MeasureString(elem.Text, elemFont);
                        //on dessine le text de l'élément, centré verticalement
                        g.TranslateTransform((float)(relpos.uix), (float)(relpos.uiy) - (elemTextSize.Height * TextYScale / 2f));
                        g.ScaleTransform(1f, TextYScale);
                        g.DrawString(elem.Text, elemFont, Brushes.Black, 0f, 0f);
                        g.ResetTransform();

                        //g.DrawString(elem.Text, elemFont, Brushes.Black, (float)(relpos.uix), (float)(relpos.uiy) - (elemTextSize.Height / 2f));
                        elemFont.Dispose();
                    }
                }

                //next iteration
                index++;
            }

            //si l'élément actuellement sélectionné a été rencontré, on dessine la flèche bleu à côté
            if (SelectedElemFound)
            {
                //make sure que l'élément actuel est sur la face visible
                if (SelectedPos.z > minimumZ)
                {
                    int arrowHeight = (int)((double)(this.imgArrow.Height) * SelectedPos.z);
                    if (arrowHeight >= this.imgArrow.Height - 5)
                    {
                        arrowHeight = this.imgArrow.Height;
                    }

                    g.DrawImage(this.imgArrow, SelectedPos.uix - 3 - this.imgArrow.Width, SelectedPos.uiy - (arrowHeight / 2), this.imgArrow.Width, arrowHeight);
                }
            }

            ////dessine les composant de l'interface graphique
            foreach (uiButton b in this.listButton)
            {
                Brush BackBrush = Brushes.Silver;
                if (b.IsMouseLeftDown)
                {
                    BackBrush = Brushes.White;
                }

                g.FillRectangle(BackBrush, b.rec);
                g.DrawRectangle(Pens.Black, b.rec);

                //dessine le text du button, au milieux
                SizeF btnTextSizeF = g.MeasureString(b.Text, this.uiBtnFont);
                g.DrawString(b.Text, this.uiBtnFont, Brushes.Black, (float)(b.Left + (b.Width / 2)) - (btnTextSizeF.Width / 2f), (float)(b.Top + (b.Height / 2)) - (btnTextSizeF.Height / 2f));
            }



            g.Dispose();
            if (this.ImageBox.Image != null)
            {
                this.ImageBox.Image.Dispose();
            }
            this.ImageBox.Image = img;
            this.ImageBox.Refresh();
        }