问题
I want to draw following string in my game
To compare, there are 10^75 particles in the universe.
where 1075 is formatted in a normalized scientific notation (as we've been doing in school).
I use SpriteBatch.DrawString method, but I cannot figure out a nite solution. There are a few trivial ones:
- Draw two strings where the second string's got a smaller font or is scaled.
- Draw an image.
I've been looking at UTF tables, but seems it's not possible.
Do I have to have special font for this task?
回答1:
I'm not familiar with XNA but in a Silverlight project where I had to do the same thing I ended up constructing scientific notation numbers from superscript characters.
You don't need a special font, just a Unicode font which has the superscript characters used below.
Heres the code to map digits 0-9 to the appropriate character:
private static string GetSuperscript(int digit)
{
switch (digit)
{
case 0:
return "\x2070";
case 1:
return "\x00B9";
case 2:
return "\x00B2";
case 3:
return "\x00B3";
case 4:
return "\x2074";
case 5:
return "\x2075";
case 6:
return "\x2076";
case 7:
return "\x2077";
case 8:
return "\x2078";
case 9:
return "\x2079";
default:
return string.Empty;
}
}
And this converts your original double into scientific notation
public static string FormatAsPowerOfTen(double? value, int decimals)
{
if(!value.HasValue)
{
return string.Empty;
}
var exp = (int)Math.Log10(value.Value);
var fmt = string.Format("{{0:F{0}}}x10{{1}}", decimals);
return string.Format(fmt, value / Math.Pow(10, exp), FormatExponentWithSuperscript(exp));
}
private static string FormatExponentWithSuperscript(int exp)
{
var sb = new StringBuilder();
bool isNegative = false;
if(exp < 0)
{
isNegative = true;
exp = -exp;
}
while (exp != 0)
{
sb.Insert(0, GetSuperscript(exp%10));
exp = exp/10;
}
if(isNegative)
{
sb.Insert(0, "-");
}
return sb.ToString();
}
So now you should be able to use FormatAsPowerOfTen(123400, 2)
resulting in 1.23x10⁵
.
回答2:
I have tweaked the answer of @Phil at some locations, and like to share my version with you.
public static string FormatAsPowerOfTen(this double? value, int decimals)
{
if (!value.HasValue)
return string.Empty;
else
return FormatAsPowerOfTen(value.Value, decimals);
}
public static string FormatAsPowerOfTen(this double value, int decimals)
{
const string Mantissa = "{{0:F{0}}}";
// Use Floor to round negative numbers so, that the number will have one digit before the decimal separator, rather than none.
var exp = Convert.ToInt32(Math.Floor(Math.Log10(value)));
string fmt = string.Format(Mantissa, decimals);
// Do not show 10^0, as this is not commonly used in scientific publications.
if (exp != 0)
fmt = string.Concat(fmt, " × 10{1}"); // Use unicode multiplication sign, rather than x.
return string.Format(fmt, value / Math.Pow(10, exp), FormatExponentWithSuperscript(exp));
}
private static string FormatExponentWithSuperscript(int exp)
{
bool isNegative = false;
var sb = new StringBuilder();
if (exp < 0)
{
isNegative = true;
exp = -exp;
}
while (exp != 0)
{
sb.Insert(0, GetSuperscript(exp % 10));
exp = exp / 10;
}
if (isNegative)
sb.Insert(0, '⁻'); //Use unicode SUPERSCRIPT minus
return sb.ToString();
}
Also, note that, due to font substitution, this method may give you ugly results for combinations of 1,2 and 3 with other digits in an exponent. 0 and 4-9 were added in unicode and are missing from many fonts. You should make sure you are using a font that supports all digits, like Arial Unicode MS, Cambria, Calibri, Consolas or Lucida Sans Unicode.
来源:https://stackoverflow.com/questions/9442243/draw-string-with-normalized-scientific-notation-superscripted