mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-22 23:12:59 +08:00
213 lines
5.6 KiB
C#
213 lines
5.6 KiB
C#
using SharpDX;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace CodeWalker.WinForms
|
|
{
|
|
public partial class QuaternionBox : UserControl
|
|
{
|
|
public QuaternionBox()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
|
|
public Quaternion Value
|
|
{
|
|
get
|
|
{
|
|
return _Value;
|
|
}
|
|
set
|
|
{
|
|
_Value = value;
|
|
UpdateFromValue();
|
|
}
|
|
}
|
|
public Vector3 EulerDeg
|
|
{
|
|
get
|
|
{
|
|
return new Vector3((float)EulerXUpDown.Value, (float)EulerYUpDown.Value, (float)EulerZUpDown.Value);
|
|
}
|
|
}
|
|
|
|
private Quaternion _Value = Quaternion.Identity;
|
|
private bool suppressEvents = false;
|
|
|
|
public event EventHandler ValueChanged;
|
|
private void RaiseValueChanged()
|
|
{
|
|
if (suppressEvents) return;
|
|
if (ValueChanged == null) return;
|
|
ValueChanged(this, null);
|
|
}
|
|
|
|
|
|
private void UpdateFromValue()
|
|
{
|
|
suppressEvents = true;
|
|
UpdateTextBox();
|
|
UpdateEulerUpDowns();
|
|
suppressEvents = false;
|
|
}
|
|
|
|
|
|
private void UpdateFromTextBox()
|
|
{
|
|
if (suppressEvents) return;
|
|
suppressEvents = true;
|
|
_Value = ParseQuaternionString(QuaternionTextBox.Text);
|
|
UpdateEulerUpDowns();
|
|
suppressEvents = false;
|
|
RaiseValueChanged();
|
|
}
|
|
|
|
private void UpdateFromEuler()
|
|
{
|
|
if (suppressEvents) return;
|
|
suppressEvents = true;
|
|
_Value = GetQuaternion(EulerXUpDown.Value, EulerYUpDown.Value, EulerZUpDown.Value);
|
|
UpdateTextBox();
|
|
suppressEvents = false;
|
|
RaiseValueChanged();
|
|
}
|
|
|
|
private void UpdateTextBox()
|
|
{
|
|
QuaternionTextBox.Text = GetQuaternionString(_Value);
|
|
}
|
|
|
|
private void UpdateEulerUpDowns()
|
|
{
|
|
var e = GetEulerAngles(_Value);
|
|
EulerXUpDown.Value = (decimal)e.X;
|
|
EulerYUpDown.Value = (decimal)e.Y;
|
|
EulerZUpDown.Value = (decimal)e.Z;
|
|
}
|
|
|
|
private void Normalize()
|
|
{
|
|
_Value.Normalize();
|
|
UpdateFromValue();
|
|
RaiseValueChanged();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static Quaternion ParseQuaternionString(string s)
|
|
{
|
|
bool tryParseFloat(string str, out float f)
|
|
{
|
|
if (float.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out f))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Quaternion q = Quaternion.Identity;
|
|
string[] ss = s.Split(',');
|
|
if (ss.Length > 0)
|
|
{
|
|
tryParseFloat(ss[0].Trim(), out q.X);
|
|
}
|
|
if (ss.Length > 1)
|
|
{
|
|
tryParseFloat(ss[1].Trim(), out q.Y);
|
|
}
|
|
if (ss.Length > 2)
|
|
{
|
|
tryParseFloat(ss[2].Trim(), out q.Z);
|
|
}
|
|
if (ss.Length > 3)
|
|
{
|
|
tryParseFloat(ss[3].Trim(), out q.W);
|
|
}
|
|
return q;
|
|
}
|
|
private static string GetQuaternionString(Quaternion q, string d = ", ")
|
|
{
|
|
var c = CultureInfo.InvariantCulture;
|
|
return q.X.ToString(c) + d + q.Y.ToString(c) + d + q.Z.ToString(c) + d + q.W.ToString(c);
|
|
}
|
|
private static Vector3 GetEulerAngles(Quaternion q)
|
|
{
|
|
var x = q.X;
|
|
var y = q.Y;
|
|
var z = q.Z;
|
|
var w = q.W;
|
|
var xx = x * x;
|
|
var yy = y * y;
|
|
var zz = z * z;
|
|
var ww = w * w;
|
|
var ls = xx + yy + zz + ww;
|
|
var st = x * w - y * z;
|
|
var sv = ls * 0.499f;
|
|
var rd = 180.0f / (float)Math.PI;
|
|
if (st > sv)
|
|
{
|
|
return new Vector3(90, (float)Math.Atan2(y, x) * 2.0f * rd, 0);
|
|
}
|
|
else if (st < -sv)
|
|
{
|
|
return new Vector3(-90, (float)Math.Atan2(y, x) * -2.0f * rd, 0);
|
|
}
|
|
else
|
|
{
|
|
return new Vector3(
|
|
(float)Math.Asin(2.0f * st) * rd,
|
|
(float)Math.Atan2(2.0f * (y * w + x * z), 1.0f - 2.0f * (xx + yy)) * rd,
|
|
(float)Math.Atan2(2.0f * (x * y + z * w), 1.0f - 2.0f * (xx + zz)) * rd
|
|
);
|
|
}
|
|
}
|
|
private static Quaternion GetQuaternion(decimal x, decimal y, decimal z)
|
|
{
|
|
var deg = new Vector3((float)x, (float)y, (float)z);
|
|
var rads = deg * (float)(Math.PI / 180.0);
|
|
return Quaternion.RotationYawPitchRoll(rads.Y, rads.X, rads.Z);
|
|
}
|
|
|
|
|
|
|
|
private void QuaternionTextBox_TextChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateFromTextBox();
|
|
}
|
|
|
|
private void EulerXUpDown_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateFromEuler();
|
|
}
|
|
|
|
private void EulerYUpDown_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateFromEuler();
|
|
}
|
|
|
|
private void EulerZUpDown_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateFromEuler();
|
|
}
|
|
|
|
private void NormalizeButton_Click(object sender, EventArgs e)
|
|
{
|
|
Normalize();
|
|
}
|
|
}
|
|
|
|
}
|