2012-01-26 22 views
6

tengo la siguiente información:Calcular centro de SVG arco

  • RadiusX (rx)
  • radiusY (RY)
  • x1
  • y1
  • x2
  • y2

La especificación SVG le permite definir un arco especificando su radio y puntos de inicio y final. Hay otras opciones como large-arc-flag y sweep-flag que ayudan a definir cómo desea que el punto de inicio llegue al punto final. More details here.

No estoy inclinado matemáticamente, por lo que comprender all of this es casi imposible.

Supongo que estoy buscando una ecuación simple que me lleve a conocer los valores centerX y centerY dados todos los argumentos aceptados por el comando de arco de SVG.

Cualquier ayuda es apreciada.

He buscado Stackoverflow y ninguna de las respuestas parece explicar la solución en inglés sencillo.

Respuesta

1

estoy considerando el caso del eje x-rotación = 0. Las ecuaciones para de inicio y finalización puntos:

x1 = cx + Rx * cos (startAngle)

y1 = cy + ry * sin (startAngle)

x2 = cx + Rx * cos (endAngle)

y2 = cy + ry * sin (endAngle)

Excluyendo ángulos desde ecuación pa

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

ry^2 * (X2: IRS nos da cx)^2 + rx^2 * (y2-cy)^2 = rx^2 * ry^2

Este sistema de ecuaciones se puede resolver analíticamente para (cx, cy) con las manos o con la ayuda de paquetes matemáticos (Maple, Mathematica etc.). Hay dos soluciones de ecuación cuadrática (debido a la combinación de gran arco de bandera y barrido de bandera).

+0

Gracias, pero tengo que admitir que no cómo resolver esa ecuación. – James

2

Puede usar esta función de javascript para calcular.

// 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

Esta es una buena implementación del apéndice SVG al que se hace referencia. Lamentablemente, no funciona en todos los casos. Hay algunos casos de borde (no muy infrecuentes) en los que el valor dentro del sqrt cuando se calcula 'coe 'es negativo. Ver 'computeArc' en http://svn.apache.org/repos/asf/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/geom/ExtendedGeneralPath.java. Tenga en cuenta que si el valor es negativo, esta implementación toma el punto central es (0,0), que parece funcionar para mí. Un ejemplo es un arco con rx = ry = 60 desde (0, 100) hasta (100, 0). – brianmearns