using System; using System.Collections.Generic; using System.Text; namespace SalsaModel { /// /// This is the thing that we draw. /// public class PositionModel { public enum Side { Left, Right }; public static string SideCode(Side side) { switch (side) { case Side.Left: return "L"; case Side.Right: return "R"; default: throw new InvalidOperationException("no such value"); } } public class Leg { public Location Toe; public Location Foot; public Location Knee; public Location Hip; public Leg Clone() { Leg ret = new Leg(); ret.Toe = Toe; ret.Foot = Foot; ret.Knee = Knee; ret.Hip = Hip; return ret; } } public Leg LLeg = new Leg(); public Leg RLeg = new Leg(); public class Arm { public Location Shoulder; public Location Elbow; public Location Wrist; public Arm Clone() { Arm ret = new Arm(); ret.Shoulder = Shoulder; ret.Elbow = Elbow; ret.Wrist = Wrist; return ret; } } public Arm RArm = new Arm(); public Arm LArm = new Arm(); public Location Head; public bool IsGirl = false; public double HipHeight; public double WallAngle = Math.PI / 2.0; public Location WallForwardsUnit { get { return new Location(1, 0, 0).RotateZ(WallAngle); } } public PositionModel Clone() { PositionModel ret = new PositionModel(); ret.LLeg = LLeg.Clone(); ret.RLeg = RLeg.Clone(); ret.LArm = LArm.Clone(); ret.RArm = RArm.Clone(); ret.Head = Head; ret.IsGirl = IsGirl; ret.HipHeight = HipHeight; ret.WallAngle = WallAngle; return ret; } public Leg GetLeg(Side side) { switch (side) { case Side.Left: return LLeg; case Side.Right: return RLeg; default: throw new Exception("can't get here"); } } public static Side Other(Side side) { switch (side) { case Side.Left: return Side.Right; case Side.Right: return Side.Left; default: throw new Exception("can't get here"); } } public Arm GetArm(Side side) { switch (side) { case Side.Left: return LArm; case Side.Right: return RArm; default: throw new Exception("can't get here"); } } public Location Neck { get { return LArm.Shoulder.HalfWayTo(RArm.Shoulder); } } public Location SidewaysUnitDirection(Side side) { return GetLeg(side).Hip.Minus(GetOtherLeg(side).Hip).SetZ(0).Normalised(); } public Location ForwardUnit() { return SidewaysUnitDirection(Side.Right).CrossProduct(new Location(0, 0, 1)); } internal Leg GetOtherLeg(Side side) { return GetLeg(Other(side)); } public Location HipMidPoint { get { return LLeg.Hip.HalfWayTo(RLeg.Hip); } } /// /// Converts a position relative to the body into an absolute world position. /// The relative position is an offset from the HipMidPoint, with the Y /// axis pointing forwards along the wall. /// /// offset from the HipMidPoint, with the Y /// axis pointing forwards along the wall. /// position in absolute space public Location RelToAbsPos(Location relativePos) { return relativePos .RotateZ(WallAngle - Math.PI/2.0) .Plus(HipMidPoint); } /// /// Converts an absolute world position into a position relative to the body. /// The relative position is an offset from the HipMidPoint, with the Y /// axis pointing forwards along the wall. /// /// position in absolute space /// offset from the HipMidPoint, with the Y /// axis pointing forwards along the wall. public Location AbsToRelPos(Location absolutePos) { return AbsToRelPos(absolutePos, HipMidPoint); } public Location AbsToRelPos(Location absolutePos, Location useHipMidPoint) { return absolutePos .Minus(useHipMidPoint) .RotateZ(-(WallAngle - Math.PI / 2.0)); } } }