diff --git a/app/Mono.cs b/app/Mono.cs index b5cc14c..637b2ff 100644 --- a/app/Mono.cs +++ b/app/Mono.cs @@ -16,8 +16,6 @@ public class Mono { // ------------------------------------------------- public dof[] dofs; - int dofIndex = 0; - dof dof => dofs[dofIndex]; public ColorCube colorCube = new ColorCube(); @@ -43,24 +41,27 @@ public class Mono { Renderer.SetClip(0.02f, 1000f); dofs = new dof[] { - // new StretchFinger(), - new WaveCursor() { handed = Handed.Left }, - new WaveCursor() { handed = Handed.Right }, - new Trackballer() { handed = Handed.Left }, - new Trackballer() { handed = Handed.Right }, - // new StretchCursor() { }, - // new StretchCursor() { }, + new Chiral() { + dofs = new dof[] { + new WaveCursor() { handed = Handed.Left }, + new WaveCursor() { handed = Handed.Right } + } + }, + new Chiral() { + dofs = new dof[] { + new Trackballer() { handed = Handed.Left }, + new Trackballer() { handed = Handed.Right } + } + }, }; } public void Init() { compositor.Init(); - dofs[0].Init(); - dofs[1].Init(); - dofs[2].Init(); - dofs[3].Init(); - + for (int i = 0; i < dofs.Length; i++) { + dofs[i].Init(); + } matDev = Material.Default.Copy(); matDev.SetTexture("diffuse", Tex.DevTex); @@ -97,21 +98,29 @@ public class Mono { // ------------------------------------------------- - // // dof.Frame(); - dofs[0].Frame(); - dofs[1].Frame(); - dofs[2].Frame(); - dofs[3].Frame(); + for (int i = 0; i < dofs.Length; i++) { + if (dofs[i].Active) { + dofs[i].Frame(); + } + } - WaveCursor lwc = (WaveCursor)dofs[0]; - WaveCursor rwc = (WaveCursor)dofs[1]; - Trackballer ltb = (Trackballer)dofs[2]; - Trackballer rtb = (Trackballer)dofs[3]; + // + WaveCursor lwc = (WaveCursor)((Chiral)dofs[0]).dofs[0]; + WaveCursor rwc = (WaveCursor)((Chiral)dofs[0]).dofs[1]; + Trackballer ltb = (Trackballer)((Chiral)dofs[1]).dofs[0]; + Trackballer rtb = (Trackballer)((Chiral)dofs[1]).dofs[1]; - lwc.Demo(ltb.ori); - rwc.Demo(rtb.ori); + if (lwc.Active) { + lwc.Demo(ltb.ori); + } + if (rwc.Active) { + rwc.Demo(rtb.ori); + } - rtb.Demo(); + if (rtb.Active) { + rtb.Demo(); + } + // // rBlock.Step(); lBlock.Step(); @@ -127,8 +136,10 @@ public class Mono { ShowWindowButton(); } + int dofIndex = 0; Pose windowPoseButton = new Pose(-0.5f, 1.3f, 0, Quat.FromAngles(0, -90f, 0)); TextStyle style = Text.MakeStyle(Font.FromFile("add/fonts/DM-Mono.ttf"), 1f * U.cm, Color.White); + TextStyle style2 = Text.MakeStyle(Font.FromFile("add/fonts/DM-Mono.ttf"), 1f * U.cm, new Color(0.5f, 0.5f, 0.5f)); Vec2 fieldSize = new Vec2(6f * U.cm, 3f * U.cm); void ShowWindowButton() { UI.WindowBegin("design vars", ref windowPoseButton); @@ -146,60 +157,128 @@ public class Mono { // UI.Label("pos.y"); // UI.HSlider("pos.y", ref playerY, -1f, 1f, 0.1f); - UI.Label("°wavecursor"); - UI.Input("wavecursor.reach", ref wcReach.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("reach"); - UI.Input("wavecursor.length", ref wcLength.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("length"); - UI.Input("wavecursor.scale", ref wcScale.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("scale"); - UI.Input("wavecursor.radius", ref wcRadius.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("radius"); + if (UI.Button("prev") && dofIndex > 0) { + dofIndex--; + } + UI.SameLine(); + if (UI.Button("next") && dofIndex < dofs.Length - 1) { + dofIndex++; + } + - UI.Label("°trackballer"); - UI.Input("trackballer.compliance", ref tbCompliance.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("compliance"); - UI.Input("trackballer.x", ref tbX.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("x"); - UI.Input("trackballer.y", ref tbY.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("y"); - UI.Input("trackballer.z", ref tbZ.str, fieldSize, TextContext.Number); - UI.SameLine(); UI.Label("z"); + dof dof = dofs[dofIndex]; + Type type = dof.GetType(); + // active toggle + Color tint = dof.Active ? new Color(0, 1, 0) : new Color(1, 0, 0); + UI.PushTint(tint); + if (UI.Button(dof.Active ? "on" : "off")) { + dof.Active = !dof.Active; + } + UI.PopTint(); + if (type == typeof(Chiral)) { + Chiral chiral = (Chiral)dof; - // flipIndex - // flipGrip + System.Reflection.FieldInfo[] fields = typeof(Chiral).GetFields(); + foreach (System.Reflection.FieldInfo field in fields) { + if (field.FieldType == typeof(Handed)) { + Handed handed = (Handed)field.GetValue(chiral); + if (UI.Button("<") && (int)handed > 0) { + handed = (Handed)((int)handed - 1); + field.SetValue(chiral, handed); + } + UI.SameLine(); + if (UI.Button(">") && (int)handed < 2) { + handed = (Handed)((int)handed + 1); + field.SetValue(chiral, handed); + } + UI.SameLine(); UI.Label(handed.ToString()); + } + } + + RenderDof(chiral.dofs[0]); + } else { + RenderDof(dof); + } UI.WindowEnd(); } - public Design wcReach = new Design("1.0", 0); - public Design wcLength = new Design("0.666", 0f, 1f); - public Design wcScale = new Design("0.333", 0.001f); - public Design wcRadius = new Design("4", 0); + void RenderDof(dof dof) { + Type type = dof.GetType(); + UI.Label("°" + type.Name); + System.Reflection.FieldInfo[] fields = type.GetFields(); + for (int j = 0; j < fields.Length; j++) { + System.Reflection.FieldInfo field = fields[j]; + if (field.FieldType == typeof(Design)) { + Design design = (Design)field.GetValue(dof); + UI.Input(field.Name, ref design.str, fieldSize, TextContext.Number); - public Design tbCompliance = new Design("0.0", 0f, 1f); - public Design tbX = new Design("1.0", -10f, 10f); - public Design tbY = new Design("2.0", -10f, 10f); - public Design tbZ = new Design("-4.0", -10f, 10f); - - // public float playerY = 0; + UI.SameLine(); + UI.PushTextStyle(style2); + UI.Label(design.term, new Vec2(4f * U.cm, 3f * U.cm)); + UI.PopTextStyle(); + UI.SameLine(); UI.Label(field.Name); + } + } + } +} + +// Chiral : handedness implies symmetry +public class Chiral : dof { + private bool active; + public bool Active { + get { return this.active; } + set { + this.active = value; + for (int i = 0; i < this.dofs.Length; i++) { + dof dof = this.dofs[i]; + if ((int)this.handed == 2 || i == (int)this.handed) { + dof.Active = value; + } else { + dof.Active = false; + } + } + } + } + public dof[] dofs = new dof[2]; + // public Design handed = new Design { str = "2", min = 0, max = 2}; + public Handed handed = Handed.Max; + + public void Init() { + dofs[0].Init(); + dofs[1].Init(); + } + + public void Frame() { + // sync the left design variables to the right + System.Reflection.FieldInfo[] fields = dofs[0].GetType().GetFields(); + foreach (System.Reflection.FieldInfo field in fields) { + if (field.FieldType == typeof(Design)) { + Design design = (Design)field.GetValue(dofs[0]); // define type? + field.SetValue(dofs[1], design); + } + } + + for (int i = 0; i < dofs.Length; i++) { + dof dof = dofs[i]; + if ((int)handed == 2 || i == (int)handed) { + dof.Frame(); + dof.Active = true; + } + else { + dof.Active = false; + } + } + } } -// convert into a class -// which also simplifies injection and persistence public class Design { public string str; - - float min, max; - public Design(string str, - float min = float.NegativeInfinity, - float max = float.PositiveInfinity - ) { - this.str = str; - this.min = min; - this.max = max; - } + public string term; + public float min = float.NegativeInfinity; + public float max = float.PositiveInfinity; + public float unit = U.m; public float value { get { @@ -207,20 +286,43 @@ public class Design { float value = PullRequest.Clamp(float.Parse(str), min, max); // if clamped, update string if (value != float.Parse(str)) { + // if (str.Contains(".")) { + // str = ""; + // } str = value.ToString(); } - return value; + return value * unit; } catch { return 0; } } } - // public int integer; + // public int integer {}; } /* COMMENTS + + ranges + 0+1 + 1-0 + 1-0+1 + + -0+ + + 0+&&- + 0+||- + + units + m + cm + mm + t + + demo + virtual shapes -> that can be slotted + physics boxes debug bool rendering the raw output diff --git a/app/dofs/dof.cs b/app/dofs/dof.cs index ba7a865..486bbb0 100644 --- a/app/dofs/dof.cs +++ b/app/dofs/dof.cs @@ -2,4 +2,5 @@ public interface dof { // ? void Init(); void Frame(); // void Drop(); + bool Active { get; set; } } \ No newline at end of file diff --git a/app/dofs/stretch-cursor/og/StretchCursor.cs b/app/dofs/stretch-cursor/og/StretchCursor.cs index e5e76f0..992b7cc 100644 --- a/app/dofs/stretch-cursor/og/StretchCursor.cs +++ b/app/dofs/stretch-cursor/og/StretchCursor.cs @@ -1,6 +1,8 @@ namespace Oriels; class StretchCursor : dof { + public bool Active { get; set; } + // input Vec3 vTo; Vec3 vFrom; diff --git a/app/dofs/stretch-cursor/wave/WaveCursor.cs b/app/dofs/stretch-cursor/wave/WaveCursor.cs index 849c4f2..9906922 100644 --- a/app/dofs/stretch-cursor/wave/WaveCursor.cs +++ b/app/dofs/stretch-cursor/wave/WaveCursor.cs @@ -1,6 +1,10 @@ namespace Oriels; class WaveCursor : dof { + public bool Active { get; set; } + + // input + public Handed handed = Handed.Left; public class Cursor { @@ -25,14 +29,15 @@ class WaveCursor : dof { float fR = Flexion(hand, FingerId.Ring); float fL = Flexion(hand, FingerId.Little); - float stretch = (fI + fI + fM + fM + fM + fR + fR + fL) / 8f; // based on finger length + // Biased by finger length + float stretch = (fI + fI + fM + fM + fM + fR + fR + fL) / 8f; Vec3 dir = PullRequest.Direction( hand.Get(FingerId.Index, JointId.Tip).position, hand.Get(FingerId.Index, JointId.KnuckleMajor).position ); - cursor.raw = hand.Get(FingerId.Index, JointId.Tip).position + dir * stretch * strength; + cursor.raw = hand.Get(FingerId.Index, JointId.Tip).position + dir * stretch * reach.value; cursor.pos.x = (float)xF.Filter(cursor.raw.x, (double)Time.Elapsedf); cursor.pos.y = (float)yF.Filter(cursor.raw.y, (double)Time.Elapsedf); cursor.pos.z = (float)zF.Filter(cursor.raw.z, (double)Time.Elapsedf); @@ -44,11 +49,14 @@ class WaveCursor : dof { } } - public float deadzone = 0.3f; - public float strength { - get { return Mono.inst.wcReach.value; } // 1f - } - public Handed handed = Handed.Left; + // design + public Design deadzone = new Design { str="0.3", term="0+1t", min=0, max=1 }; + public Design reach = new Design { str="1.0", term="0+m", min=0 }; + + // demo + public Design snakeLength = new Design { str="0.5", term="0+1t", min=0, max=1 }; + public Design snakeScale = new Design { str="0.333", term="0+", min=0 }; + public Design snakeRadius = new Design { str="4", term="0+cm", unit=U.cm, min=0 }; float Flexion(Hand hand, FingerId finger) { @@ -63,34 +71,19 @@ class WaveCursor : dof { ) ) + 1f) / 2; - return Math.Max(flexion - deadzone, 0f) / (1 - deadzone); + return Math.Max(flexion - deadzone.value, 0f) / (1 - deadzone.value); } - Vec3[] mm = new Vec3[81]; - - Vec3[] xL = new Vec3[81]; - Vec3[] xR = new Vec3[81]; - Vec3[] yL = new Vec3[81]; - Vec3[] yR = new Vec3[81]; - Vec3[] zL = new Vec3[81]; - Vec3[] zR = new Vec3[81]; + Vec3[] mm = new Vec3[128]; public void Demo(Quat ori) { - Trail( - mm, - cursor.smooth + ori * new Vec3(0, 0, Mono.inst.wcRadius.value * U.cm) - ); - - // Trail(xL, smoothPos + cursor.orientation * new Vec3(-1, 0, 0) * 0.1f); - // Trail(xR, smoothPos + cursor.orientation * new Vec3( 1, 0, 0) * 0.1f); - // Trail(yL, smoothPos + cursor.orientation * new Vec3(0, -1, 0) * 0.1f); - // Trail(yR, smoothPos + cursor.orientation * new Vec3(0, 1, 0) * 0.1f); - // Trail(zL, smoothPos + cursor.orientation * new Vec3(0, 0, -1) * 0.1f); - // Trail(zR, smoothPos + cursor.orientation * new Vec3(0, 0, 1) * 0.1f); + Vec3 tPos = cursor.smooth + ori * Vec3.Forward * snakeRadius.value; + Lines.Add(cursor.smooth, tPos, Color.White, 0.001f); + Trail(mm, tPos); } void Trail(Vec3[] points, Vec3 nextPos) { - float scale = Mono.inst.wcScale.value; + float scale = snakeScale.value; while (Vec3.Distance(points[0], nextPos) > 0.03f * scale) { for (int i = points.Length - 1; i > 0; i--) { points[i] = points[i - 1]; @@ -100,7 +93,7 @@ class WaveCursor : dof { // points[0] = nextPos; - int len = (int)(points.Length * Mono.inst.wcLength.value); + int len = (int)(points.Length * snakeLength.value); for (int i = 0; i < len; i++) { // if (i > 0) { // Vec3 dir = Vec3.Forward; diff --git a/app/dofs/trackballer/Trackballer.cs b/app/dofs/trackballer/Trackballer.cs index 06b96d4..b0b9789 100644 --- a/app/dofs/trackballer/Trackballer.cs +++ b/app/dofs/trackballer/Trackballer.cs @@ -1,6 +1,10 @@ namespace Oriels; class Trackballer : dof { + public bool Active { get; set; } + + // input + public Handed handed = Handed.Left; // data public Btn btnIn, btnOut; @@ -52,9 +56,9 @@ class Trackballer : dof { // Ball anchor HandJoint ballJoint = hand.Get(FingerId.Index, JointId.KnuckleMajor); Vec3 anchorPos = ballJoint.position + hand.palm.orientation * new Vec3( - Mono.inst.tbX.value * U.cm * (handed == Handed.Left ? -1 : 1), - Mono.inst.tbY.value * U.cm, - Mono.inst.tbZ.value * U.cm + aX.value * (handed == Handed.Left ? -1 : 1), + aY.value, + aZ.value ); anchorPos += compliance.Update( Vec3.Zero, @@ -130,8 +134,13 @@ class Trackballer : dof { // offset.z = 0; offset = hand.palm.orientation * offset; - compliance.value += offset * Mono.inst.tbCompliance.value; + compliance.value += offset * compliant.value; compliance.integral = Vec3.Zero; + } else { + PullRequest.ToAxisAngle(momentum, out Vec3 axis, out float angle); + if (angle < stop.value) { + momentum = Quat.Slerp(momentum, Quat.Identity, Time.Elapsedf * 10f); + } } } @@ -144,7 +153,12 @@ class Trackballer : dof { } // design - public Handed handed = Handed.Left; + public Design stop = new Design { str="0.05", term="0+", min=0 }; + public Design compliant = new Design { str="0.2", term="0+1t", min=0, max=1 }; + public Design aX = new Design { str=" 1.0", term="-0+cm", unit=U.cm, min=-10f, max=10f }; + public Design aY = new Design { str=" 2.0", term="-0+cm", unit=U.cm, min=-10f, max=10f }; + public Design aZ = new Design { str="-4.0", term="-0+cm", unit=U.cm, min=-10f, max=10f }; + public float[] layer = new float[] { 0.00333f, 0.02f, 0.0666f };