Hulp gevraagd voor multi-touch programma voor het roteren en schalen van plaatjes

Status
Niet open voor verdere reacties.

Elmieke

Nieuwe gebruiker
Lid geworden
24 aug 2008
Berichten
1
Voor een programma dat ik aan het schrijven ben, zoek ik onder andere een methode om plaatjes te roteren. Hier is best het een en ander over te vinden op internet, maar het probleem is dat ze hier steeds met één plaatje werken, welke via een button-click event in een picturebox getekend wordt. De code geeft aan waar en met welke rotatie. Ik heb geen bruikbare methode gevonden om een pictureBox te roteren. In het voorbeeld hieronder wordt een Graphics g gemaakt, waarbij g.DrawImage(bitmap, locatie x, locatie y, width, height) gebruikt wordt om het plaatje te tekenen en een g.Transform om het plaatje te roteren. Kan deze ‘output’ in de aangeklikt pictureBox teruggezet worden of kan de ‘output’ net als een pictureBox gebruikt worden (met click-events e.d.)? Of bestaat er toch een manier om een pictureBox rechtstreeks te roteren?

Code:
private void pictureBox1_Click(object sender, EventArgs e)
        {
            Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            Bitmap curBitmap = new Bitmap("c:\\Sinus.jpg");
            g.DrawImage(curBitmap, 0, 0, 200, 200);
            // Create a Matrix object, call its Rotate method,
            // and set it as Graphics.Transform
            Matrix X = new Matrix();
            X.Rotate(30);
            g.Transform = X;
            // Draw image
            g.DrawImage(curBitmap,
            new Rectangle(205, 0, 200, 200),
            0, 0, curBitmap.Width,
            curBitmap.Height,
            GraphicsUnit.Pixel);
            // Dispose of objects
            curBitmap.Dispose();
            g.Dispose();    
        }

In mijn geval moeten meerdere plaatjes al bij het opstarten van het programma zichtbaar zijn en real time aangepast kunnen worden. Een motion-tracking systeem geeft telkens de x, y en z coördinaten van twee punten door. Wanneer een vinger het scherm raakt en z dus een bepaalde waarde heeft, moet gekeken worden welk plaatje zich op de bijhorende x en y coördinaat bevindt. De volgende acties moeten mogelijk zijn:
• Wanneer 1 vinger het scherm raakt, kan de gebruiker het plaatje 'onder' die vinger verslepen. Bij voorkeur wordt het plaatje zo versleept dat het zelfde, aangeraakte, punt steeds onder de vinger blijft.
• Wanneer 2 vingers het scherm raken, en beide vingers bevinden zich op het plaatje, dan moeten de Width en Height van dat plaatje zo aangepast worden dat het plaatje zich tussen de twee vingers bevindt.
• Wanneer 2 vingers het scherm raken, waarvan 1 vinger zich op en 1 vinger zich naast het plaatje bevindt, dan moet het plaatje roteren. De hoek tussen een horizontale lijn en de 'onderlijn' van het plaatje moet in dat geval gelijk zijn als de hoek tussen een horizontale lijn en de lijn die je tussen de twee vingers kunt trekken. Het middelpunt van het plaatje moet op de zelfde plek blijven.
Zelf heb ik nu een programma geschreven waarbij alle plaatjes apart in een eigen pictureBox zitten en voor iedere pictureBox heb ik de volgende events opgesteld:

Code:
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                pictureBox1.BringToFront();
                btnSave.BringToFront();
                btnBackColor.BringToFront();
                Dragging = true;
                mouseX = -e.X;
                mouseY = -e.Y;
                clipLeft = this.PointToClient(MousePosition).X - pictureBox1.Location.X;
                clipTop = this.PointToClient(MousePosition).Y - pictureBox1.Location.Y;
                clipWidth = this.ClientSize.Width - (pictureBox1.Width - clipLeft);
                clipHeight = this.ClientSize.Height - (pictureBox1.Height - clipTop);
                Cursor.Clip = this.RectangleToScreen(new Rectangle(clipLeft, clipTop, clipWidth, clipHeight));
                pictureBox1.Invalidate();
                this.Cursor = Cursors.Hand;
            }
        }
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (Dragging)
            {
                Point nextPosition = new Point();
                nextPosition = this.PointToClient(MousePosition);
                nextPosition.Offset(mouseX, mouseY);
                pictureBox1.Location = nextPosition;
                this.Text = nextPosition.ToString();
            }
            if (e.Button == MouseButtons.Right)
            {
                pictureBox1.Width = this.PointToClient(MousePosition).X - pictureBox1.Location.X;
                pictureBox1.Height = this.PointToClient(MousePosition).Y - pictureBox1.Location.Y;
                pictureBox1.Invalidate();
            }
        }
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (Dragging)
            {
                Dragging = false;
                Cursor.Clip = System.Drawing.Rectangle.Empty;
                pictureBox1.Invalidate();
                this.Cursor = Cursors.Default;
            }
        }

Bij if (e.Button == MouseButtons.Left) wordt het plaatje nu versleept, maar is het de linker bovenhoek van het plaatje die op de plaats van de muis komt te liggen, in plaats van het aangeraakte punt. Dit is niet echt erg, maar als dat makkelijk verbeterd kan worden is dat natuurlijk fijn.
Bij if (e.Button == MouseButtons.Right), het vergroten/verkleinen van een plaatje, is de positie van de muis dus de positie van de ‘tweede vinger’. De eerste vinger moet dan in de linkerbovenhoek van het plaatje staan en pictureBox.Location.X en pictureBox.Location.Y vervangen.
Ik heb voor de uiteindelijke code dus nog een stuk code nodig dat bepaald of één of twee vingers het scherm raken en of hiervan één of twee vingers zich boven hetzelfde plaatje bevinden.

Een list is trouwens vast handiger, in plaats van alle plaatjes apart te nemen, maar dat kreeg ik nog niet echt uitgevogeld. Ik kan de plaatjes wel in een imageList zetten bijvoorbeeld, maar hoe beeld ik vervolgens alle plaatjes uit de list en hoe kan ik bepalen welk plaatje vervolgens geselecteerd is? Voorlopig gaat het om iets van 20 al geimporteerde plaatjes, dus dat laat ik maar even voor wat het is.

Het belangrijkste is dus dat ik wil weten hoe ik een plaatje net zo kan roteren als de hoek tussen twee vingers. Dit lijkt vast ergens op de code voor het roteren van een Grid met behulp van motion tracking met een Wii-mote (door Johnny Chung Lee, http://www.cs.cmu.edu/~johnny/projects/wii/). Maar hoe dit te gebruiken voor meerdere plaatjes die apart van elkaar te transformeren zijn, in plaats van voor een grid of een plaatje op zo’n grid?

Code:
namespace WiiMultipointGrid
{
    class AffineTransformSolver
    {
        public static float computeAngle(float dx, float dy)
        {
            float angle = 0;
            if (dx == 0)
            {
                angle = (float)Math.PI / 2;
            }
            else
            {
                if (dx > 0)
                    return (float)Math.Atan(dy / dx);
                else
                    angle = (float)(Math.Atan(dy / dx) + Math.PI);
            }
            return angle;
        }

        public static float[,] solve2Dto3x3(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
        {
            float scale = distance(x3, x4, y3, y4) / distance(x1, x2, y1, y2);
            float theta = computeAngle((x4 - x3), (y4 - y3)) - computeAngle((x2 - x1), (y2 - y1));

            float tx1 = (x2 + x1) / 2;
            float ty1 = (y2 + y1) / 2;

            float tx2 = (x4 + x3) / 2;
            float ty2 = (y4 + y3) / 2;

            float[,] result = new float[3, 3];
            result[2, 2] = 1.0f;

            result[0, 0] = (float)(scale * Math.Cos(theta));
            result[1, 0] = -(float)(scale * Math.Sin(theta));
            result[2, 0] = -tx1 * result[0, 0] - ty1 * result[1, 0] + tx2;

            result[0, 1] = (float)(scale * Math.Sin(theta));
            result[1, 1] = (float)(scale * Math.Cos(theta));
            result[2, 1] = -tx1 * result[0, 1] - ty1 * result[1, 1] + ty2;
            return result;
        }

        public static float distance(float x1, float x2, float y1, float y2)
        {
            float dx = x1- x2;
            float dy = y1-y2;
            return (float)Math.Sqrt(dx*dx+dy*dy);
        }

        public static float[,] solve2Dto4x4(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
        {
            float scale = distance(x3,x4,y3,y4) / distance(x1,x2,y1,y2);
            float theta = computeAngle((x4 - x3), (y4 - y3)) - computeAngle((x2 - x1), (y2 - y1));

            float tx1 = (x2 + x1) / 2;
            float ty1 = (y2 + y1) / 2;

            float tx2 = (x4 + x3) / 2;
            float ty2 = (y4 + y3) / 2;

            float [,] result = new float[4,4];
            result[0, 0] = 1.0f;
            result[1, 1] = 1.0f;
            result[2, 2] = 1.0f;
            result[3, 3] = 1.0f;

            result[0,0] = (float)(scale * Math.Cos(theta));
            result[1,0] = -(float)(scale * Math.Sin(theta));
            result[3,0] = -tx1 * result[0,0] - ty1 * result[1,0] + tx2;

            result[0,1] = (float)(scale * Math.Sin(theta));
            result[1,1] = (float)(scale * Math.Cos(theta));
            result[3,1] = -tx1 * result[0,1] - ty1 * result[1,1] + ty2;
            return result;
        }
    }
}

Kortom, een heel verhaal; ik kom nog veel moeilijkheden tegen. Ik heb namelijk nog niet eerder met C# gewerkt en heb ook weinig ervaring met andere programmeertalen. Het zou super zijn als iemand wat zou kunnen helpen.

Groetjes, Ellemieke
--
http://www.ellemiekevandoorn.nl

This e-mail is intended exclusively for the addressee. If you are not the addressee you must not read, copy, use or disclose the e-mail nor the content; please notify us immediately [by clicking 'Reply'] and delete this e-mail.
 
Laatst bewerkt door een moderator:
Het probleem is dat je dit niet met GDI+ (system.Drawing) opgelost gaat krijgen maar gebruik gaat moeten maken van een graphics library zoals openGL of DirectX. Het probleem hierbij is dat het bijzonder moeilijk is hiermee te werken als je nog geen programmeerervaring hebt.

Verder kan je multitouch ook niet registreren via de standaard functies van .net en ga je op zoek moeten gaan naar een wrapper of externe library.

succes
 
Laatst bewerkt:
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan