立方體可以有循環和尖角,這是二次方不可能有的。這意味着幾乎沒有簡單的解決方案。如果三次方已經是二次方,那麼存在簡單的解。通常情況下,你必須將立方分爲二次方。而且你必須決定細分的關鍵點。我在網上看到的其他消息來源表明,檢查三次樣條曲線的拐點(二次樣條不能有),並迫使它在那裏突破。在我看來,這實際上導致了結果變差,它使用更多的觀點和近似看起來並不像忽略拐點那麼接近,所以我忽略它們。「
確實如此,拐點(立方的二階導數)是不夠的。但是,如果考慮到三次函數的一階導數局部極值(最小值,最大值),以及這些全部的力斷裂,那麼子曲線都是二次的,並且可以用二次方程來表示。
我測試了下面的函數,它們按預期工作(找到立方體的所有臨界點並將立方體劃分爲向下立方體)。當繪製這些子曲線時,曲線與原始立方體完全相同,但由於某些原因,當子曲線繪製爲二次曲線時,結果幾乎是正確的,但不完全正確。
所以這個答案不是對問題的嚴格幫助,但這些函數爲立方到二次轉換提供了一個起點。
要找到當地的極端和拐點,以下get_t_values_of_critical_points()
應提供它們。所述
function compare_num(a,b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
function find_inflection_points(p1x,p1y,p2x,p2y,p3x,p3y,p4x,p4y)
{
var ax = -p1x + 3*p2x - 3*p3x + p4x;
var bx = 3*p1x - 6*p2x + 3*p3x;
var cx = -3*p1x + 3*p2x;
var ay = -p1y + 3*p2y - 3*p3y + p4y;
var by = 3*p1y - 6*p2y + 3*p3y;
var cy = -3*p1y + 3*p2y;
var a = 3*(ay*bx-ax*by);
var b = 3*(ay*cx-ax*cy);
var c = by*cx-bx*cy;
var r2 = b*b - 4*a*c;
var firstIfp = 0;
var secondIfp = 0;
if (r2>=0 && a!==0)
{
var r = Math.sqrt(r2);
firstIfp = (-b + r)/(2*a);
secondIfp = (-b - r)/(2*a);
if ((firstIfp>0 && firstIfp<1) && (secondIfp>0 && secondIfp<1))
{
if (firstIfp>secondIfp)
{
var tmp = firstIfp;
firstIfp = secondIfp;
secondIfp = tmp;
}
if (secondIfp-firstIfp >0.00001)
return [firstIfp, secondIfp];
else return [firstIfp];
}
else if (firstIfp>0 && firstIfp<1)
return [firstIfp];
else if (secondIfp>0 && secondIfp<1)
{
firstIfp = secondIfp;
return [firstIfp];
}
return [];
}
else return [];
}
function get_t_values_of_critical_points(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
c = p1x - c1x,
t1 = (-b + Math.sqrt(b * b - 4 * a * c))/2/a,
t2 = (-b - Math.sqrt(b * b - 4 * a * c))/2/a,
tvalues=[];
Math.abs(t1) > "1e12" && (t1 = 0.5);
Math.abs(t2) > "1e12" && (t2 = 0.5);
if (t1 >= 0 && t1 <= 1 && tvalues.indexOf(t1)==-1) tvalues.push(t1)
if (t2 >= 0 && t2 <= 1 && tvalues.indexOf(t2)==-1) tvalues.push(t2);
a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
c = p1y - c1y;
t1 = (-b + Math.sqrt(b * b - 4 * a * c))/2/a;
t2 = (-b - Math.sqrt(b * b - 4 * a * c))/2/a;
Math.abs(t1) > "1e12" && (t1 = 0.5);
Math.abs(t2) > "1e12" && (t2 = 0.5);
if (t1 >= 0 && t1 <= 1 && tvalues.indexOf(t1)==-1) tvalues.push(t1);
if (t2 >= 0 && t2 <= 1 && tvalues.indexOf(t2)==-1) tvalues.push(t2);
var inflectionpoints = find_inflection_points(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
if (inflectionpoints[0]) tvalues.push(inflectionpoints[0]);
if (inflectionpoints[1]) tvalues.push(inflectionpoints[1]);
tvalues.sort(compare_num);
return tvalues;
};
而當你有那些臨界噸值(它們是從範圍0-1),則可以劃分到立方部分:
function CPoint()
{
var arg = arguments;
if (arg.length==1)
{
this.X = arg[0].X;
this.Y = arg[0].Y;
}
else if (arg.length==2)
{
this.X = arg[0];
this.Y = arg[1];
}
}
function subdivide_cubic_to_cubics()
{
var arg = arguments;
if (arg.length!=9) return [];
var m_p1 = {X:arg[0], Y:arg[1]};
var m_p2 = {X:arg[2], Y:arg[3]};
var m_p3 = {X:arg[4], Y:arg[5]};
var m_p4 = {X:arg[6], Y:arg[7]};
var t = arg[8];
var p1p = new CPoint(m_p1.X + (m_p2.X - m_p1.X) * t,
m_p1.Y + (m_p2.Y - m_p1.Y) * t);
var p2p = new CPoint(m_p2.X + (m_p3.X - m_p2.X) * t,
m_p2.Y + (m_p3.Y - m_p2.Y) * t);
var p3p = new CPoint(m_p3.X + (m_p4.X - m_p3.X) * t,
m_p3.Y + (m_p4.Y - m_p3.Y) * t);
var p1d = new CPoint(p1p.X + (p2p.X - p1p.X) * t,
p1p.Y + (p2p.Y - p1p.Y) * t);
var p2d = new CPoint(p2p.X + (p3p.X - p2p.X) * t,
p2p.Y + (p3p.Y - p2p.Y) * t);
var p1t = new CPoint(p1d.X + (p2d.X - p1d.X) * t,
p1d.Y + (p2d.Y - p1d.Y) * t);
return [[m_p1.X, m_p1.Y, p1p.X, p1p.Y, p1d.X, p1d.Y, p1t.X, p1t.Y],
[p1t.X, p1t.Y, p2d.X, p2d.Y, p3p.X, p3p.Y, m_p4.X, m_p4.Y]];
}
subdivide_cubic_to_cubics()
在上面的代碼劃分的原始三次曲線到價值t的兩部分。由於get_t_values_of_critical_points()
將t值作爲按t值排序的數組返回,因此可以輕鬆遍歷所有t值並獲取相應的子曲線。當你有這些分開的曲線時,你必須將第二個子曲線除以下一個t值。
當所有分割進行時,您都有所有子曲線的控制點。現在只剩下三次控制點轉換爲二次方。因爲所有的子曲線現在都是向下升高的立方體,所以相應的二次控制點很容易計算。第一個和最後一個二次控制點與三次(次曲線)第一個和最後一個控制點相同,中間一個在點P1-P2和P4-P3相交處。
+1。你能建議一個貝塞爾曲線的參考嗎? – denis 2010-01-10 17:02:01
我使用的主要參考文獻來自我使用的CAGD類:http://tom.cs.byu.edu/~557/text/第2章介紹了貝塞爾曲線。 – tfinniga 2010-01-11 17:39:25
請問,你有這個'P1 = -1/4 Q0 + 3/4 Q1 + 3/4 Q2 - 1/4 Q3'嗎?它工作得很好... – 2012-10-26 15:26:58