2012-01-26 8 views
6

Mam następujące informacje:Oblicz centrum SVG łuku

  • radiusX (RX)
  • radiusY (ry)
  • x1
  • y1
  • x2
  • y2

Specyfikacja SVG umożliwia zdefiniowanie łuk, określając jego promień oraz punkty początkowy i końcowy. Istnieją inne opcje, takie jak large-arc-flag i sweep-flag, które pomagają określić, w jaki sposób punkt początkowy ma dotrzeć do punktu końcowego. More details here.

Nie mam skłonności matematycznych, więc zrozumienie all of this jest prawie niemożliwe.

Myślę, że szukam prostego równania, które powoduje, że znam wartości centerX i centerY ze wszystkimi argumentami zaakceptowanymi przez polecenie łuku SVG.

Każda pomoc jest doceniana.

Mam przeszukanie stackoverflow i żadna z odpowiedzi nie wydaje się wyjaśniać rozwiązania w prostym języku angielskim.

Odpowiedz

1

Zastanawiam przypadek oś x-rotacji = 0. równań dla początkowych i końcowych punktów:

x1 = cx + rx * cos (startAngle)

y1 = cy + ry * sin (startAngle)

x2 = cx + rx * cos (endAngle)

Y2 = CY + Ry * sin (endAngle)

Bez kątami równanie PA irs daje nam:

ry^2 * (x1-cx +)^2^2 * RX (Y1, CY) =^2^2 * rx ry^2

ry^2 * (x2- cx)^2 + rx^2 * (y2-cy)^2 = rx^2 * ry^2

Ten układ równań można rozwiązać analitycznie dla (cx, cy) ręcznie lub przy pomocy pakietów matematycznych (Maple, Mathematica itp.). Istnieją dwa rozwiązania równania kwadratowego (ze względu na dużą flagę i kombinację flagi wymiatającej).

+0

Dzięki, ale muszę przyznać, że nie mam sposobu rozwiązania tego równania. – James

2

Możesz użyć tej funkcji javascript do obliczenia.

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

Jest to dobra implementacja wymienionego dodatku SVG. Niestety, nie działa we wszystkich przypadkach. Istnieją pewne (niezbyt rzadkie) przypadki brzegowe, w których wartość wewnątrz sqrt przy obliczaniu 'coe' jest ujemna. Zobacz 'computeArc' w http://svn.apache.org/repos/asf/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/geom/ExtendedGeneralPath.java. Zauważ, że jeśli wartość jest ujemna, implementacja ta przyjmuje punkt środkowy (0,0), co wydaje się działać dla mnie. Przykładem jest łuk z rx = ry = 60 z (0, 100) do (100, 0). – brianmearns