I have the following information:
- radiusX (rx)
- radiusY (ry)
- x1
- y1
- x2
- y2
The SVG spec allows you to define an arc by specifying its radius, and start and end points. There are other options such as large-arc-flag
and sweep-flag
which help to define how you want the start-point to reach the end-point. More details here.
I am not mathematically inclined, so understanding all of this is near impossible.
I guess I am looking for a simple equation that results in me knowing the centerX
and centerY
values given all the arguments accepted by SVG's arc command.
Any help is appreciated.
I've search stackoverflow and none of the answers seem to explain the solution in plain english.
You can use this javascript function to calculate.
// svg : [A | a] (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
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 : svgArcToCenterParam(200,200,50,50,0,1,1,300,200)
// x1 y1 rx ry φ fA fS x2 y2
function svgArcToCenterParam(x1, y1, rx, ry, phi, fA, fS, x2, y2) {
var cx, cy, startAngle, deltaAngle, endAngle;
var PIx2 = Math.PI * 2.0;
if (rx < 0) {
rx = -rx;
}
if (ry < 0) {
ry = -ry;
}
if (rx == 0.0 || ry == 0.0) { // invalid arguments
throw Error('rx and ry can not be 0');
}
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;
// F.6.6 Correction of out-of-range radii
// Step 3: Ensure radii are large enough
var lambda = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry);
if (lambda > 1) {
rx = rx * Math.sqrt(lambda);
ry = ry * Math.sqrt(lambda);
}
var rxry = rx * ry;
var rxy1_ = rx * y1_;
var ryx1_ = ry * x1_;
var sum_of_sq = rxy1_ * rxy1_ + ryx1_ * ryx1_; // sum of square
if (!sum_of_sq) {
throw Error('start point can not be same as end point');
}
var coe = Math.sqrt(Math.abs((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
startAngle = radian(1.0, 0.0, xcr1, ycr1);
// F6.5.6
deltaAngle = radian(xcr1, ycr1, -xcr2, -ycr2);
while (deltaAngle > PIx2) { deltaAngle -= PIx2; }
while (deltaAngle < 0.0) { deltaAngle += PIx2; }
if (fS == false || fS == 0) { deltaAngle -= PIx2; }
endAngle = startAngle + deltaAngle;
while (endAngle > PIx2) { endAngle -= PIx2; }
while (endAngle < 0.0) { endAngle += PIx2; }
var outputObj = { /* cx, cy, startAngle, deltaAngle */
cx: cx,
cy: cy,
startAngle: startAngle,
deltaAngle: deltaAngle,
endAngle: endAngle,
clockwise: (fS == true || fS == 1)
}
return outputObj;
}
Usage example:
svg
<path d="M 0 100 A 60 60 0 0 0 100 0"/>
js
var result = svgArcToCenterParam(0, 100, 60, 60, 0, 0, 0, 100, 0);
console.log(result);
/* will output:
{
cx: 49.99999938964844,
cy: 49.99999938964844,
startAngle: 2.356194477985314,
deltaAngle: -3.141592627780225,
endAngle: 5.497787157384675,
clockwise: false
}
*/
I'm considering the case of x-axis-rotation = 0. Equations for start and end points:
x1 = cx + rx * cos(StartAngle)
y1 = cy + ry * sin(StartAngle)
x2 = cx + rx * cos(EndAngle)
y2 = cy + ry * sin(EndAngle)
Excluding angles from equation pairs gives us:
ry^2*(x1-cx)^2+rx^2*(y1-cy)^2=rx^2*ry^2
ry^2*(x2-cx)^2+rx^2*(y2-cy)^2=rx^2*ry^2
This equation system can be analytically solved for (cx, cy) by hands or with help of math packets (Maple, Mathematica etc). There are two solutions of quadratic equation (due to large-arc-flag and sweep-flag combination).
来源:https://stackoverflow.com/questions/9017100/calculate-center-of-svg-arc