0

我正在使用 Wiimote API,我遇到了这段代码,

 float[] srcX = new float[4];
 float[] srcY = new float[4];
 float[] dstX = new float[4];
 float[] dstY = new float[4];

我无法理解为什么会有一个由 4 个浮点数组成的数组来表示一个点。请指导。谢谢。

这是整个代码,

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;//for firing keyboard and mouse events (optional)
using System.IO;//for saving the reading the calibration data


using WiimoteLib;

namespace WiimoteWhiteboard
{
    public partial class Form1 : Form
    {
        //instance of the wii remote
        Wiimote wm = new Wiimote();

        const int smoothingBufferSize = 50;

        PointF[] smoothingBuffer = new PointF[smoothingBufferSize];
        int smoothingBufferIndex = 0;
        int smoothingAmount = 4;
        bool enableSmoothing = true;

        bool cursorControl = false;  

        int screenWidth = 1024;//defaults, gets replaced by actual screen size
        int screenHeight = 768;

        int calibrationState = 0;
        float calibrationMargin = .1f;

        CalibrationForm cf = null;

        Warper warper = new Warper();
        float[] srcX = new float[4];
        float[] srcY = new float[4];
        float[] dstX = new float[4];
        float[] dstY = new float[4];


        //declare consts for mouse messages
        public const int INPUT_MOUSE = 0;
        public const int INPUT_KEYBOARD = 1;
        public const int INPUT_HARDWARE = 2;

        public const int MOUSEEVENTF_MOVE = 0x01;
        public const int MOUSEEVENTF_LEFTDOWN = 0x02;
        public const int MOUSEEVENTF_LEFTUP = 0x04;
        public const int MOUSEEVENTF_RIGHTDOWN = 0x08;
        public const int MOUSEEVENTF_RIGHTUP = 0x10;
        public const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
        public const int MOUSEEVENTF_MIDDLEUP = 0x40;
        public const int MOUSEEVENTF_ABSOLUTE = 0x8000;

        //declare consts for key scan codes
        public const byte VK_TAB = 0x09;
        public const byte VK_MENU = 0x12; // VK_MENU is Microsoft talk for the ALT key
        public const byte VK_SPACE = 0x20;
        public const byte VK_RETURN = 0x0D;
        public const byte VK_LEFT  =0x25;
        public const byte VK_UP     =0x26;
        public const byte VK_RIGHT  =0x27;
        public const byte VK_DOWN   =0x28;
        public const int KEYEVENTF_EXTENDEDKEY = 0x01;
        public const int KEYEVENTF_KEYUP = 0x02;

        //for firing mouse and keyboard events
        [DllImport("user32.dll", SetLastError = true)]
        static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

        [StructLayout(LayoutKind.Sequential)]
        public struct MOUSEINPUT
        {
            public int dx;//4
            public int dy;//4
            public uint mouseData;//4
            public uint dwFlags;//4
            public uint time;//4
            public IntPtr dwExtraInfo;//4
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct KEYBDINPUT
        {
            public ushort wVk;//2
            public ushort wScan;//2
            public uint dwFlags;//4
            public uint time;//4
            public IntPtr dwExtraInfo;//4
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct HARDWAREINPUT
        {
            public uint uMsg;
            public ushort wParamL;
            public ushort wParamH;
        }

        [StructLayout(LayoutKind.Explicit, Size = 28)]
        public struct INPUT
        {
            [FieldOffset(0)]
            public int type;
            [FieldOffset(4)] //*
            public MOUSEINPUT mi;
            [FieldOffset(4)] //*
            public KEYBDINPUT ki;
            [FieldOffset(4)] //*
            public HARDWAREINPUT hi;
        }
        //imports mouse_event function from user32.dll

        [DllImport("user32.dll")]
        private static extern void mouse_event(
        long dwFlags, // motion and click options
        long dx, // horizontal position or change
        long dy, // vertical position or change
        long dwData, // wheel movement
        long dwExtraInfo // application-defined information
        );

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetCursorPos(int X, int Y);

        //imports keybd_event function from user32.dll
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void keybd_event(byte bVk, byte bScan, long dwFlags, long dwExtraInfo);
        WiimoteState lastWiiState = new WiimoteState();//helps with event firing

        //end keyboard and mouse input emulation variables----------------------------------------

        Mutex mut = new Mutex();

        public Form1()
        {
            screenWidth = Screen.GetBounds(this).Width;
            screenHeight = Screen.GetBounds(this).Height;
            InitializeComponent();

            for (int i = 0; i < smoothingBufferSize; i++)
                smoothingBuffer[i] = new PointF();

            setSmoothing(smoothingAmount);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //add event listeners to changes in the wiiremote
            //fired for every input report - usually 100 times per second if acclerometer is enabled
            wm.WiimoteChanged += new WiimoteChangedEventHandler(wm_OnWiimoteChanged); 
            //fired when the extension is attached on unplugged
            wm.WiimoteExtensionChanged += new WiimoteExtensionChangedEventHandler(wm_OnWiimoteExtensionChanged);

            try
            {
                //connect to wii remote
                wm.Connect();

                //set what features you want to enable for the remote, look at Wiimote.InputReport for options
                wm.SetReportType(Wiimote.InputReport.IRAccel, true);


                //set wiiremote LEDs with this enumerated ID
                wm.SetLEDs(true, false, false, false);
            }
            catch (Exception x)
            {
                MessageBox.Show("Exception: " + x.Message);
                this.Close();
            }
            loadCalibrationData();
        }

        void wm_OnWiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
        {

            //if extension attached, enable it
            if(args.Inserted)
                wm.SetReportType(Wiimote.InputReport.IRExtensionAccel, true);
            else
                wm.SetReportType(Wiimote.InputReport.IRAccel, true);
        }

        float UpdateTrackingUtilization()
        {
            //area of ideal calibration coordinates (to match the screen)
            float idealArea = (1 - 2*calibrationMargin) * 1024 * (1 - 2*calibrationMargin) * 768;

            //area of quadrliatera
            float actualArea = 0.5f * Math.Abs((srcX[1] - srcX[2]) * (srcY[0] - srcY[3]) - (srcX[0] - srcX[3]) * (srcY[1] - srcY[2]));
            float util = (actualArea / idealArea)*100;
            BeginInvoke((MethodInvoker)delegate() { lblTrackingUtil.Text = util.ToString("f0"); });
            BeginInvoke((MethodInvoker)delegate() { pbTrackingUtil.Value = (int)util; });

            return util;

        }

        PointF getSmoothedCursor(int amount)
        {
            int start = smoothingBufferIndex - amount;
            if (start < 0)
                start = 0;
            PointF smoothed = new PointF(0,0);
            int count = smoothingBufferIndex - start;
            for (int i = start; i < smoothingBufferIndex; i++)
            {
                smoothed.X += smoothingBuffer[i%smoothingBufferSize].X;
                smoothed.Y += smoothingBuffer[i % smoothingBufferSize].Y;
            }
            smoothed.X /= count;
            smoothed.Y /= count;
            return smoothed;
        }

        void wm_OnWiimoteChanged(object sender, WiimoteChangedEventArgs args)
        {
            mut.WaitOne();

            //extract the wiimote state
            WiimoteState ws = args.WiimoteState;

            if (ws.IRState.Found1)
            {
                int x = ws.IRState.RawX1;
                int y = ws.IRState.RawY1;
                float warpedX = x;
                float warpedY = y;
                warper.warp(x, y, ref warpedX, ref warpedY);

                smoothingBuffer[smoothingBufferIndex % smoothingBufferSize].X = warpedX;
                smoothingBuffer[smoothingBufferIndex % smoothingBufferSize].Y = warpedY;
                smoothingBufferIndex++;

                if (!lastWiiState.IRState.Found1)//mouse down
                {
                    lastWiiState.IRState.Found1 = ws.IRState.Found1;
                    smoothingBufferIndex = 0;//resets the count

                    if (cursorControl)
                    {
                        INPUT[] buffer = new INPUT[2];
                        buffer[0].type = INPUT_MOUSE;
                        buffer[0].mi.dx = (int)(warpedX *65535.0f/screenWidth);
                        buffer[0].mi.dy = (int)(warpedY * 65535.0f / screenHeight);
                        buffer[0].mi.mouseData = 0;
                        buffer[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
                        buffer[0].mi.time = 0;
                        buffer[0].mi.dwExtraInfo = (IntPtr)0;

                        buffer[1].type = INPUT_MOUSE;
                        buffer[1].mi.dx = 0;
                        buffer[1].mi.dy = 0;
                        buffer[1].mi.mouseData = 0;
                        buffer[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
                        buffer[1].mi.time = 1;
                        buffer[1].mi.dwExtraInfo = (IntPtr)0;

                        SendInput(2, buffer, Marshal.SizeOf(buffer[0]));

                    }//cusor control

                    switch (calibrationState)
                    {
                        case 1:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 2;
                            doCalibration();
                            break;
                        case 2:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 3;
                            doCalibration();
                            break;
                        case 3:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 4;
                            doCalibration();
                            break;
                        case 4:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 5;
                            doCalibration();
                            break;
                        default:
                            break;
                    }//calibtation state
                }//mouse down                
                else
                {
                    if (cursorControl)//dragging
                    {
                        INPUT[] buffer = new INPUT[1];
                        buffer[0].type = INPUT_MOUSE;
                        if (enableSmoothing)
                        {
                            PointF s = getSmoothedCursor(smoothingAmount);
                            buffer[0].mi.dx = (int)(s.X * 65535.0f / screenWidth);
                            buffer[0].mi.dy = (int)(s.Y * 65535.0f / screenHeight);
                        }
                        else
                        {
                            buffer[0].mi.dx = (int)(warpedX * 65535.0f / screenWidth);
                            buffer[0].mi.dy = (int)(warpedY * 65535.0f / screenHeight);
                        }
                        buffer[0].mi.mouseData = 0;
                        buffer[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
                        buffer[0].mi.time = 0;
                        buffer[0].mi.dwExtraInfo = (IntPtr)0;
                        SendInput(1, buffer, Marshal.SizeOf(buffer[0]));

                    }
                }
            }//ir visible
            else
            {
                if (lastWiiState.IRState.Found1)//mouse up
                {
                    lastWiiState.IRState.Found1 = ws.IRState.Found1;
                    if (cursorControl)
                    {
                        INPUT[] buffer = new INPUT[2];
                        buffer[0].type = INPUT_MOUSE;
                        buffer[0].mi.dx = 0;
                        buffer[0].mi.dy = 0;
                        buffer[0].mi.mouseData = 0;
                        buffer[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
                        buffer[0].mi.time = 0;
                        buffer[0].mi.dwExtraInfo = (IntPtr)0;

                        buffer[1].type = INPUT_MOUSE;
                        buffer[1].mi.dx = 0;
                        buffer[1].mi.dy = 0;
                        buffer[1].mi.mouseData = 0;
                        buffer[1].mi.dwFlags = MOUSEEVENTF_MOVE;
                        buffer[1].mi.time = 0;
                        buffer[1].mi.dwExtraInfo = (IntPtr)0;

                        SendInput(2, buffer, Marshal.SizeOf(buffer[0]));

                    }
                }//ir lost
            }
            if (!lastWiiState.ButtonState.A && ws.ButtonState.A)
            {
                BeginInvoke((MethodInvoker)delegate() { btnCalibrate.PerformClick(); });
            }
            lastWiiState.ButtonState.A = ws.ButtonState.A;

            if (!lastWiiState.ButtonState.B && ws.ButtonState.B)
                keybd_event(VK_SPACE, 0x45, 0, 0);
            if (lastWiiState.ButtonState.B && !ws.ButtonState.B)
                keybd_event(VK_SPACE, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.B = ws.ButtonState.B;

            if (!lastWiiState.ButtonState.Up && ws.ButtonState.Up)
                keybd_event(VK_UP, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Up && !ws.ButtonState.Up)
                keybd_event(VK_UP, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Up = ws.ButtonState.Up;

            if (!lastWiiState.ButtonState.Down && ws.ButtonState.Down)
                keybd_event(VK_DOWN, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Down && !ws.ButtonState.Down)
                keybd_event(VK_DOWN, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Down = ws.ButtonState.Down;

            if (!lastWiiState.ButtonState.Left && ws.ButtonState.Left)
                keybd_event(VK_LEFT, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Left && !ws.ButtonState.Left)
                keybd_event(VK_LEFT, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Left = ws.ButtonState.Left;

            if (!lastWiiState.ButtonState.Right && ws.ButtonState.Right)
                keybd_event(VK_RIGHT, 0x45, 0, 0);
            if (lastWiiState.ButtonState.Right && !ws.ButtonState.Right)
                keybd_event(VK_RIGHT, 0x45, KEYEVENTF_KEYUP, 0);
            lastWiiState.ButtonState.Right = ws.ButtonState.Right;


            lastWiiState.IRState.Found1 = ws.IRState.Found1;
            lastWiiState.IRState.RawX1 = ws.IRState.RawX1;
            lastWiiState.IRState.RawY1 = ws.IRState.RawY1;
            lastWiiState.IRState.Found2 = ws.IRState.Found2;
            lastWiiState.IRState.RawX2 = ws.IRState.RawX2;
            lastWiiState.IRState.RawY2 = ws.IRState.RawY2;
            lastWiiState.IRState.Found3 = ws.IRState.Found3;
            lastWiiState.IRState.RawX3 = ws.IRState.RawX3;
            lastWiiState.IRState.RawY3 = ws.IRState.RawY3;
            lastWiiState.IRState.Found4 = ws.IRState.Found4;
            lastWiiState.IRState.RawX4 = ws.IRState.RawX4;
            lastWiiState.IRState.RawY4 = ws.IRState.RawY4;

            //draw battery value on GUI
            //BeginInvoke((MethodInvoker)delegate() { pbBattery.Value = (ws.Battery > 0xc8 ? 0xc8 : (int)ws.Battery); });
            //float f = (((100.0f * 48.0f * (float)(ws.Battery / 48.0f))) / 192.0f);
            //BeginInvoke((MethodInvoker)delegate() { lblBattery.Text = f.ToString("f0") + "%"; });

            //check the GUI check boxes if the IR dots are visible
            //String irstatus = "Visible IR dots: ";
            //if (ws.IRState.Found1)
            //    irstatus += "1 ";
            //if (ws.IRState.Found2)
            //    irstatus += "2 ";
            //if (ws.IRState.Found3)
            //    irstatus += "3 ";
            //if (ws.IRState.Found4)
            //    irstatus += "4 ";

            //BeginInvoke((MethodInvoker)delegate() { lblIRvisible.Text = irstatus; });

            mut.ReleaseMutex();        
        }


        public void loadCalibrationData()
        {
            // create reader & open file
            try
            {
                TextReader tr = new StreamReader("calibration.dat");
                for (int i = 0; i < 4; i++)
                {
                    srcX[i] = float.Parse(tr.ReadLine());
                    srcY[i] = float.Parse(tr.ReadLine());
                }
                smoothingAmount = int.Parse(tr.ReadLine());

                // close the stream
                tr.Close();
            }
            catch (Exception x)
            {
                //no prexsting calibration 
                return;
            }

            warper.setDestination(  screenWidth * calibrationMargin,
                                    screenHeight * calibrationMargin,
                                    screenWidth * (1.0f-calibrationMargin),
                                    screenHeight * calibrationMargin,
                                    screenWidth * calibrationMargin,
                                    screenHeight * (1.0f - calibrationMargin),
                                    screenWidth * (1.0f - calibrationMargin),
                                    screenHeight * (1.0f - calibrationMargin));
            warper.setSource(srcX[0], srcY[0], srcX[1], srcY[1], srcX[2], srcY[2], srcX[3], srcY[3]);

            warper.computeWarp();

            setSmoothing(smoothingAmount);

            cursorControl = true;
           // BeginInvoke((MethodInvoker)delegate() { cbCursorControl.Checked = cursorControl; });

            UpdateTrackingUtilization();
        }

        public void saveCalibrationData()
        {
            TextWriter tw = new StreamWriter("calibration.dat");

            // write a line of text to the file
            for (int i = 0; i < 4; i++)
            {
                tw.WriteLine(srcX[i]);
                tw.WriteLine(srcY[i]);
            }
            tw.WriteLine(smoothingAmount);
            // close the stream
            tw.Close();
        }

        public void doCalibration(){
            if (cf == null)
                return;
            int x = 0;
            int y = 0;
            int size = 25;
            Pen p = new Pen(Color.Red);
            switch (calibrationState)
            {
                case 1:
                    x = (int)(screenWidth * calibrationMargin);
                    y = (int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 2:
                    x = screenWidth - (int)(screenWidth * calibrationMargin);
                    y = (int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 3:
                    x = (int)(screenWidth * calibrationMargin);
                    y = screenHeight -(int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 4:
                    x = screenWidth - (int)(screenWidth * calibrationMargin);
                    y = screenHeight -(int)(screenHeight * calibrationMargin);
                    cf.showCalibration(x, y, size, p);
                    dstX[calibrationState - 1] = x;
                    dstY[calibrationState - 1] = y;
                    break;
                case 5:
                    //compute warp
                    warper.setDestination(dstX[0], dstY[0], dstX[1], dstY[1], dstX[2], dstY[2], dstX[3], dstY[3]);
                    warper.setSource(srcX[0], srcY[0], srcX[1], srcY[1], srcX[2], srcY[2], srcX[3], srcY[3]);
                    warper.computeWarp();
                    cf.Close();
                    cf = null;
                    calibrationState = 0;
                    cursorControl = true;
                   // BeginInvoke((MethodInvoker)delegate() { cbCursorControl.Checked = cursorControl; });
//                    saveCalibrationData();
                    UpdateTrackingUtilization();
                    break;
                default:
                    break;
            }

        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            //disconnect the wiimote
            wm.Disconnect();
            saveCalibrationData();
        }

        private void btnCalibrate_Click(object sender, EventArgs e)
        {
            if (cf == null)
            {
                cf = new CalibrationForm();
                cf.Show();
            }
            if (cf.IsDisposed)
            {
                cf = new CalibrationForm();
                cf.Show();
            }
            cursorControl = false;
            calibrationState = 1;
            doCalibration();
        }

        private void cbCursorControl_CheckedChanged(object sender, EventArgs e)
        {
            //cursorControl = cbCursorControl.Checked;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void setSmoothing(int smoothing)
        {
            smoothingAmount = smoothing;
            //trackBar1.Value = smoothing;
            enableSmoothing = (smoothingAmount != 0);
           // lblSmoothing.Text = "Smoothing: " + smoothingAmount;
        }

        //private void trackBar1_Scroll(object sender, EventArgs e)
        //{

        //    smoothingAmount = trackBar1.Value;
        //    enableSmoothing = (smoothingAmount != 0);
        //    lblSmoothing.Text = "Smoothing: " + smoothingAmount;
        //}

        private void lblIRvisible_Click(object sender, EventArgs e)
        {

        }
    }
}
4

1 回答 1

0

它用于通过矩阵计算进行校准。

Warper猜实际上处理矩阵转换以校准屏幕位置等。

矩阵是 4x4 --> 4 个大小为 4 的数组。

在这里您可以查看代码

于 2013-10-12T07:23:52.777 回答