Advertisement
StanHebben

Example motion controller

Dec 1st, 2016
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.71 KB | None | 0 0
  1.  
  2. private IMyRemoteControl remoteControl;
  3. private bool isOverrideEnabled = false;
  4.  
  5. private MotionDriver motionDriver;
  6. private MovingMotionController motionController;
  7.  
  8. private List<Vector3D> recordedPositions = new List<Vector3D>();
  9. private int recordedPositionIndex = 0;
  10. private bool landing = false;
  11. private Vector3D positionBeforeLanding;
  12.  
  13. public Program()
  14. {
  15. remoteControl = GetBlock<IMyRemoteControl>("Remote Control");
  16. motionDriver = new MotionDriver(remoteControl, this, 95);
  17. motionController = new MovingMotionController(remoteControl);
  18. }
  19.  
  20. public void Main(string argument)
  21. {
  22. if (argument == "Toggle")
  23. isOverrideEnabled = !isOverrideEnabled;
  24.  
  25. if (argument == "Record")
  26. recordedPositions.Add(remoteControl.GetPosition());
  27.  
  28. if (argument == "Next") {
  29. if (recordedPositions.Count == 0)
  30. return;
  31.  
  32. motionController.MoveTo(recordedPositions[recordedPositionIndex]);
  33. recordedPositionIndex = (recordedPositionIndex + 1) % recordedPositions.Count;
  34. }
  35.  
  36. if (argument == "Land") {
  37. landing = !landing;
  38. if (landing) {
  39. double distance;
  40. if (remoteControl.TryGetPlanetElevation(MyPlanetElevation.Surface, out distance)) {
  41. Vector3D down = remoteControl.GetNaturalGravity();
  42. down.Normalize();
  43.  
  44. distance -= 10; // center position to bottom - adjust this or you'll crash into the floor
  45. positionBeforeLanding = remoteControl.GetPosition();
  46. Vector3D targetPosition = remoteControl.GetPosition() + distance * down;
  47. motionController.MoveTo(targetPosition);
  48. motionDriver.SetController(motionController);
  49. } else {
  50. landing = false;
  51. }
  52. } else {
  53. motionController.MoveTo(positionBeforeLanding);
  54. }
  55. }
  56.  
  57. if (isOverrideEnabled)
  58. motionDriver.SetController(motionController);
  59. else
  60. motionDriver.SetController(null);
  61.  
  62. motionDriver.Tick();
  63. }
  64.  
  65. private class MovingMotionController : MotionController
  66. {
  67. private readonly Quaternion orientation;
  68. private Vector3D target;
  69. private Action whenFinished;
  70.  
  71. public MovingMotionController(IMyShipController shipController)
  72. {
  73. this.orientation = Quaternion.CreateFromRotationMatrix(shipController.CubeGrid.WorldMatrix);
  74. this.target = shipController.GetPosition();
  75. }
  76.  
  77. public void MoveTo(Vector3D target, Action whenFinished = null)
  78. {
  79. this.target = target;
  80. this.whenFinished = whenFinished;
  81. }
  82.  
  83. public MotionDriver.MotionTarget Tick(MotionDriver.MotionState state, double delta)
  84. {
  85. return new MotionDriver.MotionTarget(target, Vector3D.Zero, orientation);
  86. }
  87.  
  88. public void OnArrived(MotionDriver.MotionState state)
  89. {
  90. if (whenFinished != null) {
  91. whenFinished();
  92. whenFinished = null;
  93. }
  94. }
  95.  
  96. public string Serialize()
  97. {
  98. return "";
  99. }
  100. }
  101.  
  102.  
  103. public interface MotionController{MotionDriver.MotionTarget Tick(MotionDriver.MotionState s,double d);void OnArrived(MotionDriver.MotionState s);string Serialize();}
  104. public delegate MotionController MotionControllerDeserializer(string s);
  105. public class MotionDriver{
  106. public class MotionState{
  107. public readonly double Time,BaseMass,TotalMass,PowerPosX,PowerPosY,PowerPosZ,PowerNegX,PowerNegY,PowerNegZ;
  108. public readonly Vector3D Position,VelocityLocal,VelocityWorld,AngularVelocityWorldYPR,AngularVelocityLocalYPR,GravityWorld,GravityLocal;
  109. public readonly Quaternion Orientation,AngularVelocityWorld,AngularVelocityLocal;
  110. public readonly Matrix WorldMatrix,WorldMatrixInverse;
  111. public MotionState(MotionDriver d){Time=d.TM;Position=d.SC.GetPosition();Orientation=Quaternion.CreateFromRotationMatrix(d.SC.WorldMatrix.GetOrientation());BaseMass=d.B;TotalMass=d.M;WorldMatrix=d.SC.WorldMatrix;WorldMatrixInverse=MatrixD.Invert(this.WorldMatrix);PowerPosX=d.PX;PowerPosY=d.PY;PowerPosZ=d.PZ;PowerNegX=d.NX;PowerNegY=d.NY;PowerNegZ=d.NZ;var v=d.SC.GetShipVelocities();VelocityWorld=v.LinearVelocity;VelocityLocal=Vector3D.TransformNormal(VelocityWorld,WorldMatrixInverse);AngularVelocityWorldYPR=v.AngularVelocity;Quaternion.CreateFromYawPitchRoll((float)-AngularVelocityWorldYPR.Y,(float)AngularVelocityWorldYPR.X,(float)-AngularVelocityWorldYPR.Z,out AngularVelocityWorld);AngularVelocityLocalYPR=Vector3D.TransformNormal(AngularVelocityLocalYPR,WorldMatrixInverse);Quaternion.CreateFromYawPitchRoll((float)-AngularVelocityLocalYPR.Y,(float)AngularVelocityLocalYPR.X,(float)-AngularVelocityLocalYPR.Z,out AngularVelocityLocal);GravityWorld=d.SC.GetNaturalGravity();GravityLocal=Vector3D.TransformNormal(GravityWorld,WorldMatrixInverse);}
  112. }
  113.  
  114. public struct MotionTarget{
  115. public static MotionTarget ToPosition(Vector3D p){return new MotionTarget(p,null,null);}
  116. public static MotionTarget Linear(Vector3D p,Vector3D s){return new MotionTarget(p,s,null);}
  117. public static MotionTarget Orientation(Quaternion o){return new MotionTarget(null,null,o);}
  118. public readonly Vector3D? Position;public readonly Vector3D Speed;public readonly Quaternion? Rotation;
  119. public MotionTarget(string s){string[] i=s.Split(':');Position=i[0].Length==0?null:(Vector3D?)Serializer.ParseVector(i[0]);Speed=i[1].Length==0?Vector3D.Zero:Serializer.ParseVector(i[1]);Rotation = i[2].Length == 0 ? null : (Quaternion?)Serializer.ParseQuaternion(i[2]);}
  120. public MotionTarget(Vector3D? p,Vector3D? s,Quaternion? r){Position=p;Speed=s??Vector3D.Zero;Rotation=r;}
  121. public string Serialize(){var r=new StringBuilder();if(Position.HasValue)r.Append(Serializer.SerializeVector(Position.Value));r.Append(":");if(Speed!=Vector3D.Zero)r.Append(Serializer.SerializeVector(Speed));r.Append(":");if(Rotation.HasValue)r.Append(Serializer.SerializeQuaternion(Rotation.Value));return r.ToString();}
  122. }
  123.  
  124. public double positionPrecision = 0.02;
  125. public double velocityPrecision = 0.1;
  126. public double angularPrecision = 0.001;
  127. public Vector3D rotationDampening = new Vector3D(0.5, 0.5, 0.5);
  128. public Vector3D angularCorrectionFactor = new Vector3D(5, 5, 5);
  129.  
  130. private void InitThrusterPowers(){
  131. register("SmallBlockSmallThrust",12000,0,1,1,.3);
  132. register("SmallBlockLargeThrust",144000,0,1,1,.3);
  133. register("LargeBlockSmallThrust",288000,0,1,1,.3);
  134. register("LargeBlockLargeThrust",3600000,0,1,1,.3);
  135. register("SmallBlockLargeHydrogenThrust",400000,0,1,1,1);
  136. register("SmallBlockSmallHydrogenThrust",82000,0,1,1,1);
  137. register("LargeBlockLargeHydrogenThrust",6000000,0,1,1,1);
  138. register("LargeBlockSmallHydrogenThrust", 900000,0,1,1,1);
  139. register("SmallBlockLargeAtmosphericThrust",408000,.3,1,0,1,true);
  140. register("SmallBlockSmallAtmosphericThrust",80000,.3,1,0,1,true);
  141. register("LargeBlockLargeAtmosphericThrust",5400000,.3,1,0,1,true);
  142. register("LargeBlockSmallAtmosphericThrust",420000,.3,1,0,1,true);
  143. }
  144.  
  145. private const int TR=6;private const double TT=1.0/60.0,D=TT*TR,D2=D*D/2;private readonly Dictionary<string,ThrusterInfo>TH=new Dictionary<string,ThrusterInfo>();private readonly IMyShipController SC;private readonly Program P;private readonly double MS;public readonly List<IMyGyro>G=new List<IMyGyro>();public readonly List<IMyThrust>T=new List<IMyThrust>();private int TI=0;private MotionController MC;private bool GO=false,GH=false,TS=false,ED=false;private double B,M,AD=1.0,AA=8000,TM=0,PX=0,NX=0,PY=0,NY=0,PZ=0,NZ=0;
  146. public MotionDriver(IMyShipController s,Program p,double m){SC=s;P=p;MS=m;InitThrusterPowers();}
  147. public MotionDriver(IMyShipController s,Program p,double m,string t,MotionControllerDeserializer d):this(s,p,m){if(t==null||t.Length==0)return;var e=t.Split(":".ToCharArray(),2);SetController(d(e[1]),double.Parse(e[0]));}
  148. private void register(string s,double f,double a,double b,double c,double d,bool n=false){TH[s]=new ThrusterInfo(f,a,b,c,d,n);}
  149. public MotionState GetState(){return new MotionState(this);}
  150. public void SetPlanetAtmosphere(double d,double a){this.AD=d;this.AA=a;}
  151. public void SetController(MotionController c,double t=0){this.TM=t;this.MC=c;}
  152. public string Serialize(){return String.Format("{0:0.00}:{1}",TM,MC.Serialize());}
  153. public void Tick(){TI++;if((TI%60)==1)UP();if((TI%60)==2)UM();if((TI%60)==3)UT();if((TI%60)==4)UG();if((TI%6)!=0)return;if(MC==null){CT();SG(false);return;}var s=GetState();var t=MC.Tick(s, D);var a=true;if(t.Position.HasValue||t.Speed.LengthSquared()>0)a&=T1(s, t);else CT();if(t.Rotation.HasValue)a&=G1(s,t);else SG(false);if(a)MC.OnArrived(s);TM+=D;}
  154. private bool T1(MotionState s,MotionTarget t){var w=MatrixD.Invert(SC.WorldMatrix);var v=s.VelocityLocal;var p=Vector3D.Transform(s.Position,w);var g=s.GravityLocal;var u=t.Speed;var x=Vector3D.Transform(t.Position??(s.Position+(u+v)*D*.66),w);var a=u-v;var b=x-p;if(a.LengthSquared()<velocityPrecision&&b.LengthSquared()<positionPrecision){CT();SD(true);return true;}var c=GA(a)+g;var d=a/c;var e=p+v*d+c*d*d/2;var f=x-e;var h=GA(f);var i=h+g;var j=(f-v*D)/D2-g;var o=Vector3D.Max(-Vector3D.One,Vector3D.Min(Vector3D.One,.5*j/h))*100;if(f.X<0)o.X=-o.X;if(f.Y<0)o.Y=-o.Y;if(f.Z<0)o.Z=-o.Z;if(v.LengthSquared()>=MS*MS&&(o*v).Min()>=-.01){CT();return false;}SD(d.Max()<D);TO(o);return false;}
  155. private Vector3D GA(Vector3D d){return new Vector3D((d.X>0?PX:-NX)/M,(d.Y>0?PY:-NY)/M,(d.Z>0?PZ:-NZ)/M);}
  156. private bool G1(MotionState s,MotionTarget t){var a=Quaternion.Inverse(t.Rotation.Value);var b=s.Orientation;var d=Math.Abs(b.X-a.X)+Math.Abs(b.Y-a.Y)+Math.Abs(b.Z-a.Z)+Math.Abs(b.W-a.W);SG(true);bool h=d<angularPrecision&&s.AngularVelocityLocalYPR.LengthSquared()<angularPrecision;HG(h);if(h)return true;foreach(var g in G){var c=CG(g,a);var w=MatrixD.Invert(g.WorldMatrix);var x=Vector3D.TransformNormal(s.AngularVelocityWorldYPR,w);var y=c*angularCorrectionFactor;
  157. var z=y-s.AngularVelocityLocalYPR*rotationDampening;g.SetValueFloat("Yaw",-(float)z.Y);g.SetValueFloat("Pitch",(float)z.X);g.SetValueFloat("Roll",-(float)z.Z);}return false;}
  158. private void UT(){T.Clear();P.GridTerminalSystem.GetBlocksOfType(T,t=>t.IsWorking&&t.CubeGrid==SC.CubeGrid);}
  159. private void UG(){G.Clear();P.GridTerminalSystem.GetBlocksOfType(G,g=>g.IsWorking&&g.CubeGrid==SC.CubeGrid);}
  160. private void SG(bool g){if(g==GO)return;GO=g;foreach(var y in G)y.SetValueBool("Override",g);}
  161. private void HG(bool h){if(h==GH)return;GH=h;foreach(var y in G){y.SetValueFloat("Yaw",0);y.SetValueFloat("Pitch",0);y.SetValueFloat("Roll",0);}}
  162. private void CT(){if(TS)return;TS=true;foreach(var t in T)t.SetValueFloat("Override",0);}
  163. private void TO(Vector3D o){TS=false;var a=SC.Orientation;foreach(var t in T){var d=a.TransformDirectionInverse(Base6Directions.GetFlippedDirection(t.Orientation.Forward));switch(d){case Base6Directions.Direction.Right:t.SetValueFloat("Override",Math.Max(0,(float)o.X));break;case Base6Directions.Direction.Left:t.SetValueFloat("Override",Math.Max(0,(float)-o.X));break;case Base6Directions.Direction.Up:t.SetValueFloat("Override", Math.Max(0,(float)o.Y));break;case Base6Directions.Direction.Down:t.SetValueFloat("Override", Math.Max(0,(float)-o.Y));break;case Base6Directions.Direction.Backward:t.SetValueFloat("Override", Math.Max(0,(float)o.Z));break;case Base6Directions.Direction.Forward:t.SetValueFloat("Override",Math.Max(0,(float)-o.Z));break;}}}
  164. private void UP(){PX=0;NX=0;PY=0;NY=0;PZ=0;NZ=0;bool a = false;var b=.0;double d;if(SC.TryGetPlanetElevation(MyPlanetElevation.Sealevel,out d)){a=d<AA;if(a)b=PA(d);}var c=SC.Orientation;foreach(var t in T){var e=c.TransformDirectionInverse(Base6Directions.GetFlippedDirection(t.Orientation.Forward));var f=TH.GetValueOrDefault(t.BlockDefinition.SubtypeId);if(f==null){P.Echo("Unknown thruster type: "+t.BlockDefinition.SubtypeId);continue;}var g=f.GetPower(a,b);switch(e){case Base6Directions.Direction.Right:PX+=g;break;case Base6Directions.Direction.Left:NX+=g;break;case Base6Directions.Direction.Up:PY+=g;break;case Base6Directions.Direction.Down:NY+=g;break;case Base6Directions.Direction.Backward:PZ+=g;break;case Base6Directions.Direction.Forward:NZ+=g;break;}}}
  165. private void UM(){var m=SC.CalculateShipMass();B=m.BaseMass;M=m.TotalMass;}
  166. private Vector3D CG(IMyGyro g,Quaternion o){Quaternion a;g.Orientation.GetQuaternion(out a);return QY(Quaternion.CreateFromRotationMatrix(MatrixD.Transform(g.WorldMatrix,a*o)));}
  167. private Vector3D QY(Quaternion r){var t=MatrixD.CreateFromQuaternion(r);var x=new Vector3D();MatrixD.GetEulerAnglesXYZ(ref t,out x);return x;}
  168. private double CR(double r){if(r>Math.PI)return r-2*Math.PI;if(r<-Math.PI)return r+2*Math.PI;return r;}
  169. private void SD(bool e){if(e==ED)return;ED=e;SC.SetValueBool("DampenersOverride",e);}
  170. private double PA(double a){return MathHelper.Clamp(1.0-a/AA,.0,1.0)*AD;}
  171. }
  172.  
  173. public class ThrusterInfo{
  174. public readonly double Force,MinPlanetaryInfluence,MaxPlanetaryInfluence,EffectivenessAtMinInfluence,EffectivenessAtMaxInfluence;public readonly bool NeedsAtmosphereForInfluence;
  175. public ThrusterInfo(double f,double a,double b,double c,double d,bool n){Force=f;MinPlanetaryInfluence=a;MaxPlanetaryInfluence=b;EffectivenessAtMinInfluence=c;EffectivenessAtMaxInfluence=d;NeedsAtmosphereForInfluence=n;}
  176. public double GetPower(bool a,double b){if(!a)return NeedsAtmosphereForInfluence?0:Force*EffectivenessAtMinInfluence;if(EffectivenessAtMinInfluence==EffectivenessAtMaxInfluence)return Force*EffectivenessAtMaxInfluence;var x=MathHelper.Clamp((b-MinPlanetaryInfluence)/(MaxPlanetaryInfluence - MinPlanetaryInfluence),0f,1f);return Force*MathHelper.Lerp(EffectivenessAtMinInfluence,EffectivenessAtMaxInfluence,x);}
  177. }
  178.  
  179. public static class Serializer{
  180. public static string SerializeVector(Vector3D v){return String.Format("{0:0.000} {1:0.000} {2:0.000}",v.X,v.Y,v.Z);}
  181. public static string SerializeQuaternion(Quaternion q){return String.Format("{0:0.000} {1:0.000} {2:0.000} {3:0.000}",q.X,q.Y,q.Z,q.W);}
  182. public static string SerializeMatrix(MatrixD m){return String.Format("{0:0.000} {1:0.000} {2:0.000} {3:0.000} {4:0.000} {5:0.000} {6:0.000} {7:0.000} {8:0.000} {9:0.000} {10:0.000} {11:0.000} {12:0.000} {13:0.000} {14:0.000} {15:0.000}",m.M11,m.M12,m.M13,m.M14,m.M21,m.M22,m.M23,m.M24,m.M31,m.M32,m.M33,m.M34,m.M41,m.M42,m.M43,m.M44);}
  183. public static string SerializeDetectedEntity(MyDetectedEntityInfo e){return String.Format("{0}:{1}:{2}:{3}:{4}:{5}:{6}:{7}:{8}:{9}",SerializeVector(e.BoundingBox.Min),SerializeVector(e.BoundingBox.Max),e.EntityId,e.HitPosition.HasValue ? SerializeVector(e.HitPosition.Value) : "",e.Name.Replace(':', ' '),SerializeMatrix(e.Orientation),(int)e.Relationship,e.TimeStamp,(int)e.Type,SerializeVector(e.Velocity));}
  184. public static Vector3D ParseVector(string s){var c=s.Split(' ');return new Vector3D(double.Parse(c[0]),double.Parse(c[1]),double.Parse(c[2]));}
  185. public static Quaternion ParseQuaternion(string s){var c=s.Split(' ');return new Quaternion(float.Parse(c[0]),float.Parse(c[1]),float.Parse(c[2]),float.Parse(c[3]));}
  186. public static MatrixD ParseMatrix(string s){var c=s.Split(' ');return new MatrixD(double.Parse(c[0]),double.Parse(c[1]),double.Parse(c[2]),double.Parse(c[3]),double.Parse(c[4]),double.Parse(c[5]),double.Parse(c[6]),double.Parse(c[7]),double.Parse(c[8]),double.Parse(c[9]),double.Parse(c[10]),double.Parse(c[11]),double.Parse(c[12]),double.Parse(c[13]), double.Parse(c[14]), double.Parse(c[15]));}
  187. public static MyDetectedEntityInfo ParseDetectedEntity(string s){var p=s.Split(':');return new MyDetectedEntityInfo(long.Parse(p[2]),p[4],(MyDetectedEntityType)int.Parse(p[8]),p[3].Length==0?(Vector3D?)null:ParseVector(p[3]),ParseMatrix(p[5]),ParseVector(p[9]), (MyRelationsBetweenPlayerAndBlock)int.Parse(p[6]),new BoundingBoxD(ParseVector(p[0]),ParseVector(p[1])),long.Parse(p[7]));}
  188. public static string StripPrefix(string v,string p){if (!v.StartsWith(p))throw new InvalidOperationException("Value doesn't start with the given prefix");return v.Substring(p.Length);}
  189. }
  190.  
  191. public T GetBlock<T>(string n) where T:class,IMyTerminalBlock{var r=GridTerminalSystem.GetBlockWithName(n) as T;if(r==null)Echo("Could not find "+n);return r;}
  192.  
  193. public class VariableFontTextPanel {
  194. public IMyTextPanel Panel;public float FontSize,BaseWidth,ScaledWidth;
  195. public VariableFontTextPanel(IMyTextPanel p,float w){Panel=p;BaseWidth=w;}
  196. public void Reset(){Panel.WritePublicText("");Panel.ShowPublicTextOnScreen();FontSize=Panel.GetValue<float>("FontSize");ScaledWidth=BaseWidth/FontSize;}
  197. public void Print(string t){Panel.WritePublicText(t,true);}
  198. public void Print(string t,params object[]a){Panel.WritePublicText(a.Length==0?t:string.Format(t,a),true);}
  199. public void PrintLn(string t){Panel.WritePublicText(t+"\n",true);}
  200. public void PrintLn(string t, params object[]a){Panel.WritePublicText((a.Length==0?t:string.Format(t,a))+'\n',true);}
  201. public void Indent(double p){Panel.WritePublicText(new string(' ',(int)(p/StringFunctions.WHITESPACE_WIDTH/FontSize)),true);}
  202. public void PrintLnCentered(string t){Indent((ScaledWidth-StringFunctions.MeasureStringLength(t))*0.5f);PrintLn(t);}
  203. public void PrintLnCentered(string t,params object[]a){PrintLnCentered(string.Format(t, a));}
  204. public void PrintWrapped(string t){var a=0f;var b=0;for(int c=0;c<t.Length;c++){a+=StringFunctions.GetCharSize(t[c]);if(a>ScaledWidth){PrintLn(t.Substring(b,c-b));b=c;a=StringFunctions.GetCharSize(t[c]);}}Print(t.Substring(b));}
  205. public void PrintLnProgress(double r){PrintLn(MakeProgressBar(r,ScaledWidth*FontSize));}
  206. public void PrintProgress(double r, double w){Print(MakeProgressBar(r, w));}
  207. public string MakeProgressBar(double r, double w){r=Math.Max(0f,Math.Min(1f,r));var a=w/FontSize-18f;int bars=Math.Max(0,(int)((a*r)/StringFunctions.PROGRESSCHAR_WIDTH));int b=Math.Max(0,(int)((a-bars*StringFunctions.PROGRESSCHAR_WIDTH)/StringFunctions.WHITESPACE_WIDTH));return"["+new string('|',bars)+new string(' ',b)+']';}
  208. }
  209.  
  210. public static class StringFunctions {
  211. private static Dictionary<char, float> cs;
  212. public const float WHITESPACE_WIDTH=8f,PROGRESSCHAR_WIDTH=6.4f,ELLIPSIS_WIDTH = 31f;
  213. static StringFunctions(){cs=new Dictionary<char,float>();A("3FKTabdeghknopqsuy£µÝàáâãäåèéêëðñòóôõöøùúûüýþÿaaaddeeeeegggghhKknnn?ooosssšTTTuuuuuuYyŸ???????????????????",17);A("#0245689CXZ¤¥ÇßCCCCZZŽƒ???????????????€",19);A("$&GHPUVY§ÙÚÛÜÞAGGGGHHUUUUUU???????†‡",20);A("ABDNOQRSÀÁÂÃÄÅÐÑÒÓÔÕÖØAADÐNNNOOORRRSSSŠ??????",21);A("(),.1:;[]ft{}·ttt?",9);A("+<=>E^~¬±¶ÈÉÊË×÷EEEEE?????-",18);A(" !I`ijl¡¨¯´¸ÌÍÎÏìíîïIiIiIiIijllllˆ???°?˜?????‹›·",8);A("7?Jcz¢¿çccccJzzž????????????????",16);A("L_vx«»LLL?L???????–•",15);A("\"-rª­º?rrr",10);A("mw¼w??",27);A("M??",26);A("WÆŒW—…‰",31);A("'|¦¯‘’‚",6);A("*²³¹", 11);A("\\°“”„",12);A("/????",14);A("%??",24);A("@©®???", 25);A("\n",0);A("¾æœ?",28);A("½?",29);A("?",7);A("?", 22);A("?",13);A("?",23);A("™",30);}
  214. private static void A(string c,float s){for(int i=0;i<c.Length;i++)cs.Add(c[i],s/0.8f);}
  215. public static float GetCharSize(char c){float w=40;cs.TryGetValue(c,out w);return w;}
  216. public static float MeasureStringLength(string s){float a=0;for(int i=0;i<s.Length;i++)a+=GetCharSize(s[i]);return a;}
  217. public static string Ellipsize(string t,float p){var a=MeasureStringLength(t);if(a<=p)return t;a+=ELLIPSIS_WIDTH;int b=t.Length;while(a>p){b--;a-=GetCharSize(t[b]);}return t.Substring(0,b)+"…";}
  218. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement