2012-01-26 20 views
6

ho le seguenti informazioni:Calcolare centro di SVG dell'arco

  • RadiusX (rx)
  • radiusY (ry)
  • x1
  • Y1
  • x2
  • Y2

Le specifiche SVG consentono di definire un arco specificandone il raggio e i punti iniziale e finale. Esistono altre opzioni come large-arc-flag e sweep-flag che aiutano a definire come si desidera che il punto iniziale raggiunga il punto finale. More details here.

Non sono matematicamente inclinato, quindi capire all of this è quasi impossibile.

Immagino che sto cercando una semplice equazione che mi porta a conoscere i valori e centerY dati tutti gli argomenti accettati dal comando arc di SVG.

Qualsiasi aiuto è apprezzato.

Ho uno stackoverflow di ricerca e nessuna delle risposte sembra spiegare la soluzione in inglese.

risposta

1

Sto considerando il caso di asse x-rotazione = 0. Equazioni per punti iniziale e finale:

x1 = cx + RX * cos (startAngle)

y1 = cy + ry * sin (startAngle)

x2 = cx + rx * cos (endAngle)

y2 = cy + ry * sin (endAngle)

Esclusione angoli da equazione pa

ry^2 * (x1-cx)^2 + rx^2 * (Y1-cy)^2 = rx^2 * ry^2

ry^2 * (X2-: IRS ci dà cx)^2 + rx^2 * (y2-cy)^2 = rx^2 * ry^2

Questo sistema di equazioni può essere risolto analiticamente per (cx, cy) con le mani o con l'aiuto di pacchetti matematici (Acero, Mathematica ecc.). Esistono due soluzioni di equazione quadratica (a causa della combinazione di flag con arco di grandi dimensioni e bandiera a bandiera).

+0

Grazie, ma devo ammettere che non so come risolvere questa equazione. – James

2

È possibile utilizzare questa funzione javascript per calcolare.

// svg : [A | a] (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ 

/* x1 y1 x2 y2 fA fS rx ry φ */ 
function radian(ux, uy, vx, vy) { 
    var dot = ux * vx + uy * vy; 
    var mod = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); 
    var rad = Math.acos(dot/mod); 
    if(ux * vy - uy * vx < 0.0) rad = -rad; 
    return rad; 
} 
//conversion_from_endpoint_to_center_parameterization 
//sample : convert(200,200,300,200,1,1,50,50,0,{}) 
function convert(x1, y1, x2, y2, fA, fS, rx, ry, phi) { 
     var cx,cy,theta1,delta_theta; 

     if(rx == 0.0 || ry == 0.0) return -1; // invalid arguments 

     var s_phi = Math.sin(phi); 
     var c_phi = Math.cos(phi); 
     var hd_x = (x1 - x2)/2.0; // half diff of x 
     var hd_y = (y1 - y2)/2.0; // half diff of y 
     var hs_x = (x1 + x2)/2.0; // half sum of x 
     var hs_y = (y1 + y2)/2.0; // half sum of y 

     // F6.5.1 
     var x1_ = c_phi * hd_x + s_phi * hd_y; 
     var y1_ = c_phi * hd_y - s_phi * hd_x; 

     var rxry = rx * ry; 
     var rxy1_ = rx * y1_; 
     var ryx1_ = ry * x1_; 
     var sum_of_sq = rxy1_ * rxy1_ + ryx1_ * ryx1_; // sum of square 
     var coe = Math.sqrt((rxry * rxry - sum_of_sq)/sum_of_sq); 
     if(fA == fS) coe = -coe; 

     // F6.5.2 
     var cx_ = coe * rxy1_/ry; 
     var cy_ = -coe * ryx1_/rx; 

     // F6.5.3 
     cx = c_phi * cx_ - s_phi * cy_ + hs_x; 
     cy = s_phi * cx_ + c_phi * cy_ + hs_y; 

     var xcr1 = (x1_ - cx_)/rx; 
     var xcr2 = (x1_ + cx_)/rx; 
     var ycr1 = (y1_ - cy_)/ry; 
     var ycr2 = (y1_ + cy_)/ry; 

     // F6.5.5 
     theta1 = radian(1.0, 0.0, xcr1, ycr1); 

     // F6.5.6 
     delta_theta = radian(xcr1, ycr1, -xcr2, -ycr2); 
     var PIx2 = Math.PI * 2.0; 
     while(delta_theta > PIx2) delta_theta -= PIx2; 
     while(delta_theta < 0.0) delta_theta += PIx2; 
     if(fS == false) delta_theta -= PIx2; 

     var outputObj = { /* cx, cy, theta1, delta_theta */ 
      cx : cx, 
      cy : cy, 
      theta1 : theta1, 
      delta_theta : delta_theta 
     } 
     console.dir(outputObj); 

     return outputObj; 
} 
+1

Questa è una buona implementazione dell'appendice SVG di riferimento. Sfortunatamente, non funziona in tutti i casi. Ci sono alcuni casi di bordo (non molto rari) in cui il valore all'interno di sqrt quando si calcola 'coe' è negativo. Vedi 'computeArc' in http://svn.apache.org/repos/asf/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/geom/ExtendedGeneralPath.java. Si noti che se il valore è negativo, questa implementazione prende il punto centrale è (0,0), che sembra funzionare per me. Un esempio è un arco con rx = ry = 60 da (0, 100) a (100, 0). – brianmearns

Problemi correlati