2008-08-13 28 views
9

वर्तमान में, मैं एकाधिक बेजियरों को समतुल्य बिंदु बनाने की कोशिश कर रहा हूं। मैं वर्तमान में अंक खोजने के लिए क्यूबिक इंटरपोलेशन का उपयोग कर रहा हूं, लेकिन क्योंकि बेजियर काम करते हैं, कुछ क्षेत्रों में दूसरों की तुलना में अधिक घना होता है और परिवर्तनीय दूरी की वजह से बनावट मैपिंग के लिए सकल साबित होता है। क्या प्रतिशत के बजाए दूरी से बेजियर पर अंक खोजने का कोई तरीका है? इसके अलावा, क्या यह एकाधिक जुड़े घटता को विस्तारित करना संभव है?बेजियर घटता में समतुल्य बिंदु

+0

भी http://math.stackexchange.com/a/61796/589 देखें। – lhf

उत्तर

4

P_0 और P_3 (घन रूप में) के बीच दूरी, हाँ, लेकिन मुझे लगता है कि आप जानते थे कि, सीधे आगे है।

fig 1 http://www.codecogs.com/eq.latex?%5Cint_%7Bt_0%7D%5E%7Bt_1%7D%20%7B%20|P'(t)|%20dt

जहां:

एक वक्र पर दूरी सिर्फ चाप लंबाई है

fig 2 http://www.codecogs.com/eq.latex?P%27(t)%20=%20[%7Bx%27,y%27,z%27%7D]%20=%20[%7B%5Cfrac%7Bdx(t)%7D%7Bdt%7D,%5Cfrac%7Bdy(t)%7D%7Bdt%7D,%5Cfrac%7Bdz(t)%7D%7Bdt%7D%7D]

(see the rest)

शायद, आप चाहते हैं t_0 = 0, T_1 = 1.0, और डीजे (टी) = 0 (2 डी विमान)।

+5

इस प्रकार आप पैरामीटर दिए गए आर्क लंबाई को पाते हैं, लेकिन समतुल्य बिंदुओं को ढूंढने के लिए इस फ़ंक्शन के विपरीत की आवश्यकता होती है। एक से दूसरे तक हो जाना तुच्छ नहीं है। @ क्रिस्टियन रोमो: आपने यह कैसे किया? मेरा मतलब है, आप केवल बाइनरी खोज का उपयोग कर सकते हैं, लेकिन यह बहुत धीमा होगा (जो भी मैं करने की कोशिश कर रहा हूं, वैसे भी)। – CromTheDestroyer

9

इसे "आर्क लंबाई" पैरामीटरकरण कहा जाता है। मैं कई साल पहले इस बारे में एक पत्र लिखा:

http://www.saccade.com/writing/graphics/RE-PARAM.PDF

विचार पूर्व गणना करने के लिए एक "parameterization" वक्र, और कहा कि के माध्यम से की अवस्था का मूल्यांकन है।

+0

अभी तक पूरी तरह से कागज नहीं पढ़ा है। लेकिन मैं यह पूछना चाहता हूं कि वक्र को परिभाषित करने का बेहतर तरीका है जिसे पहले "रूपांतरित" करने की आवश्यकता नहीं होगी। जैसे क्या आप जानते हैं कि क्या मैं सभी पथ/घटता को परिभाषित करने के लिए NURBS का उपयोग करता हूं, क्या यह तेजी से समतुल्य चाप लंबाई parametrization का समर्थन करेगा? या शायद कुछ और रास्ता? संपादित करें: तेजी से मेरा मतलब है सीपीयू या जीपीयू का उपयोग करना। – Ciantic

+0

एनयूआरबी का उपयोग करने से मदद नहीं मिलेगी, मौलिक समस्या एक जैसी है। पेपर का अंत मूल के साथ पुनः पैरामीटरकरण वक्र लिखने की एक विधि दिखाता है। यह आर्क-लम्बा पैरामीटर के साथ एक नया वक्र उत्पन्न करता है, लेकिन वक्र अधिक होने पर ऑर्डर देता है, इसलिए यह मूल्यांकन करने में धीमा है। –

2

मैं जानता हूँ कि यह एक पुराने सवाल है, लेकिन मैं हाल ही में इस समस्या का सामना किया और एक UIBezierPath विस्तार बनाई गई एक X के लिए हल करने के लिए एक Y दिया निर्देशांक समन्वय और विपरीत शिकंजा। तेजी से लिखा है।

https://github.com/rkotzy/RKBezierMath

extension UIBezierPath { 

func solveBezerAtY(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, y: CGFloat) -> [CGPoint] { 

    // bezier control points 
    let C0 = start.y - y 
    let C1 = point1.y - y 
    let C2 = point2.y - y 
    let C3 = end.y - y 

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D 
    let A = C3 - 3.0*C2 + 3.0*C1 - C0 
    let B = 3.0*C2 - 6.0*C1 + 3.0*C0 
    let C = 3.0*C1 - 3.0*C0 
    let D = C0 

    let roots = solveCubic(A, b: B, c: C, d: D) 

    var result = [CGPoint]() 

    for root in roots { 
     if (root >= 0 && root <= 1) { 
      result.append(bezierOutputAtT(start, point1: point1, point2: point2, end: end, t: root)) 
     } 
    } 

    return result 
} 

func solveBezerAtX(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, x: CGFloat) -> [CGPoint] { 

    // bezier control points 
    let C0 = start.x - x 
    let C1 = point1.x - x 
    let C2 = point2.x - x 
    let C3 = end.x - x 

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D 
    let A = C3 - 3.0*C2 + 3.0*C1 - C0 
    let B = 3.0*C2 - 6.0*C1 + 3.0*C0 
    let C = 3.0*C1 - 3.0*C0 
    let D = C0 

    let roots = solveCubic(A, b: B, c: C, d: D) 

    var result = [CGPoint]() 

    for root in roots { 
     if (root >= 0 && root <= 1) { 
      result.append(bezierOutputAtT(start, point1: point1, point2: point2, end: end, t: root)) 
     } 
    } 

    return result 

} 

func solveCubic(a: CGFloat?, var b: CGFloat, var c: CGFloat, var d: CGFloat) -> [CGFloat] { 

    if (a == nil) { 
     return solveQuadratic(b, b: c, c: d) 
    } 

    b /= a! 
    c /= a! 
    d /= a! 

    let p = (3 * c - b * b)/3 
    let q = (2 * b * b * b - 9 * b * c + 27 * d)/27 

    if (p == 0) { 
     return [pow(-q, 1/3)] 

    } else if (q == 0) { 
     return [sqrt(-p), -sqrt(-p)] 

    } else { 

     let discriminant = pow(q/2, 2) + pow(p/3, 3) 

     if (discriminant == 0) { 
      return [pow(q/2, 1/3) - b/3] 

     } else if (discriminant > 0) { 
      let x = crt(-(q/2) + sqrt(discriminant)) 
      let z = crt((q/2) + sqrt(discriminant)) 
      return [x - z - b/3] 
     } else { 

      let r = sqrt(pow(-(p/3), 3)) 
      let phi = acos(-(q/(2 * sqrt(pow(-(p/3), 3))))) 

      let s = 2 * pow(r, 1/3) 

      return [ 
       s * cos(phi/3) - b/3, 
       s * cos((phi + CGFloat(2) * CGFloat(M_PI))/3) - b/3, 
       s * cos((phi + CGFloat(4) * CGFloat(M_PI))/3) - b/3 
      ] 

     } 

    } 
} 

func solveQuadratic(a: CGFloat, b: CGFloat, c: CGFloat) -> [CGFloat] { 

    let discriminant = b * b - 4 * a * c; 

    if (discriminant < 0) { 
     return [] 

    } else { 
     return [ 
      (-b + sqrt(discriminant))/(2 * a), 
      (-b - sqrt(discriminant))/(2 * a) 
     ] 
    } 

} 

private func crt(v: CGFloat) -> CGFloat { 
    if (v<0) { 
     return -pow(-v, 1/3) 
    } 
    return pow(v, 1/3) 
} 

private func bezierOutputAtT(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint { 

    // bezier control points 
    let C0 = start 
    let C1 = point1 
    let C2 = point2 
    let C3 = end 

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D 
    let A = CGPointMake(C3.x - 3.0*C2.x + 3.0*C1.x - C0.x, C3.y - 3.0*C2.y + 3.0*C1.y - C0.y) 
    let B = CGPointMake(3.0*C2.x - 6.0*C1.x + 3.0*C0.x, 3.0*C2.y - 6.0*C1.y + 3.0*C0.y) 
    let C = CGPointMake(3.0*C1.x - 3.0*C0.x, 3.0*C1.y - 3.0*C0.y) 
    let D = C0 

    return CGPointMake(((A.x*t+B.x)*t+C.x)*t+D.x, ((A.y*t+B.y)*t+C.y)*t+D.y) 
} 

// TODO: - future implementation 
private func tangentAngleAtT(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, t: CGFloat) -> CGFloat { 

    // bezier control points 
    let C0 = start 
    let C1 = point1 
    let C2 = point2 
    let C3 = end 

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D 
    let A = CGPointMake(C3.x - 3.0*C2.x + 3.0*C1.x - C0.x, C3.y - 3.0*C2.y + 3.0*C1.y - C0.y) 
    let B = CGPointMake(3.0*C2.x - 6.0*C1.x + 3.0*C0.x, 3.0*C2.y - 6.0*C1.y + 3.0*C0.y) 
    let C = CGPointMake(3.0*C1.x - 3.0*C0.x, 3.0*C1.y - 3.0*C0.y) 

    return atan2(3.0*A.y*t*t + 2.0*B.y*t + C.y, 3.0*A.x*t*t + 2.0*B.x*t + C.x) 
} 

}