[英]How to draw text onto a jpg and resave it using system.drawing in c#
[英]Why does this C# function to draw a sine wave using System.Drawing overflows?
因此,我制作了一個繪制正弦波的小窗口窗體程序,但是當我放置某些函數(例如sin(x) ^ x
它會溢出)。 請查看此代碼,並幫助我解決該問題!
private void button1_Click(object sender, EventArgs e)
{
if (Completed) return;
Completed = true;
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Brushes.Black, 2.0F);
float x1 = 0;
float y1 = 0;
float y2 = 0;
float yEx = 300;
float eF = 50;
for (float x = 0; x < Width; x += 0.005F)
{
y2 = (float)Math.Pow(Math.Sin(x) , x);
g.DrawLine(pen, x1 * eF, y1 * eF + yEx, x * eF, y2 * eF + yEx);
x1 = x;
y1 = y2;
}
}
任何貢獻表示贊賞!
好吧,事實證明,解決方案是TyCobb的答案和John Wu的答案的結合。 當您對x
等遞增值使用Math.Sin
時, Math.Sin(x)
的輸出大約一半Math.Sin(x)
負數。 當您在第一個參數中給它一個負數而在第二個參數中給它一個非整數時, Math.Pow
不喜歡它(在這種情況下,它將返回NaN
)。 這樣做的原因是因為當您將負數加一個非整數時,結果是一個復數。
現在Graphics.DrawLine
不在乎是否將NaN
作為第二對float
參數( x2, y2
)中的任何一個傳遞x2, y2
因為它會不做任何事情而返回。 但是,如果您將NaN
作為第一對( x1, y1
)中的一個傳遞,它將拋出OverflowException
。 我不確定為什么要這樣做,但我願意猜測這是.NET團隊過去的疏忽。
現在,從第一個發現中,您可以看到問題主要出在x
為負數時。 一種簡單的解決方案是用Math.Pow(x)
替換x
,但這可能會以不反映原始函數意圖的方式更改輸出。 第二種解決方案是簡單地跳過這些迭代,但這會在圖形中留下漏洞。
您可能已經猜到的第三個解決方案是,用Complex.Pow
替換Math.Pow
。 通過返回一個復數,這將為您可能需要的冪輸入提供支持。 完成此操作后,您可以選擇要對結果執行的操作。 (我只是將結果的“ Real
部分作為y
並丟棄了“ Imaginary
部分。)
for (float x = 0; x < Width; x += 0.005F)
{
y2 = (float)Complex.Pow(Math.Sin(x), x).Real;
g.DrawLine(pen, x1 * eF, y1 * eF + yEx, x * eF, y2 * eF + yEx);
x1 = x;
y1 = y2;
}
結果是這樣的:
驗證DrawLine
的值。
您在循環處檢查Width
,但是在調用DrawLine
之前不驗證計算。 這是一個沒有抽獎的例子:
float x1 = 0;
float y1 = 0;
float y2 = 0;
float yEx = 300;
float eF = 50;
const int width = 1024;
const int height = 1024;
for (float x = 0; x < width; x += 0.005F)
{
y2 = (float)Math.Pow(Math.Sin(x) , x);
var a = x1 * eF;
var b = y1 * eF + yEx;
var c = x * eF;
var d = y2 * eF + yEx;
if(a < 0 || a >= width || b < 0 || b >= height || c < 0 || c >= width || d < 0 || d > height)
Console.WriteLine("Snap! {0} | {1} | {2} | {3}", a, b, c, d);
x1 = x;
y1 = y2;
}
當您嘗試脫掉畫布時,GDI不會幫您,實際上,它通常會蓬勃發展。 您應該始終將值限制在高度和寬度之內。
這是該示例的一些要點:
Snap! 1101,215 | NaN | 1101,465 | NaN
Snap! 1101,465 | NaN | 1101,715 | NaN
Snap! 1101,715 | NaN | 1101,965 | NaN
Snap! 1101,965 | NaN | 1102,215 | NaN
Snap! 1102,215 | NaN | 1102,465 | NaN
Snap! 1102,465 | NaN | 1102,715 | NaN
Snap! 1102,715 | NaN | 1102,965 | NaN
Snap! 1102,965 | NaN | 1103,215 | NaN
Snap! 1103,215 | NaN | 1103,465 | NaN
Snap! 1103,465 | NaN | 1103,715 | NaN
Snap! 1103,715 | NaN | 1103,965 | NaN
Snap! 1103,965 | NaN | 1104,215 | NaN
Snap! 1104,215 | NaN | 1104,465 | NaN
Snap! 1104,465 | NaN | 1104,715 | NaN
Snap! 1104,715 | NaN | 1104,965 | NaN
Snap! 1104,965 | NaN | 1105,215 | NaN
問題是Math.Pow有時返回的浮點數不是數字或NaN 。 特別:
x <0,但不是NegativeInfinity; y不是整數,NegativeInfinity或PositiveInfinity。 = NaN
由於Sin(x)將繪制一條同時在0之上和以下的曲線,因此其某些值將為負,因此Math.Pow
調用將產生NaN,這當然不能在笛卡爾空間上繪制。
我建議您按如下方式臨時修改代碼:用try塊包裝draw調用。
try
{
g.DrawLine(pen, x1 * eF, y1 * eF + yEx, x * eF, y2 * eF + yEx);
}
catch {} //Not usually a great idea to eat all exceptions, but for troubleshooting purposes this'll do
然后運行您的代碼並查看該行。 該行中的中斷將告訴您域/范圍的哪些部分有問題。 全面了解計算問題后,您可以將笛卡爾空間變換/映射到不會發生溢出的域中,例如,通過向SIN函數的結果中添加常量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.