求椭圆弧参数转换算法, Conversion from endpoint to center parameterization

时间:2022-02-18 17:03:43
我在看SVG SPEC里面看到这一段转换,但是我没理解,谁能用代码来实现一下这个转换吗?

svg里面绘制椭圆弧的参数是这样的:x1 y1 x2 y2 fA fS rx ry φ
分别代表的含义是:
(x1 y1)圆弧路径起点
(x2 y2)圆弧路径终点
fA 标记是否大弧段
fS 标记是否顺时针绘制
rx 椭圆弧的X半轴长度
ry 椭圆弧的Y半轴长度
φ 椭圆弧X轴方向的旋转角度

我需要的计算是,根据上述参数,计算出:
椭圆弧的中心点(cx,cy)
起始弧度 θ1  
终点弧度与起点弧度的差  Δθ



网址:
http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes

英文原文:
F.6.5 Conversion from endpoint to center parameterization

Given the following variables:

x1 y1 x2 y2 fA fS rx ry φ

the task is to find:

cx cy θ1 Δθ

The equations simplify after a translation which places the origin at the midpoint of the line joining (x1, y1) to (x2, y2), followed by a rotation to line up the coordinate axes with the axes of the ellipse. All transformed coordinates will be written with primes. They are computed as intermediate values on the way toward finding the required center parameterization variables. This procedure consists of the following steps:

    Step 1: Compute (x1′, y1′)
     求椭圆弧参数转换算法, Conversion from endpoint to center parameterizationEquation F.6.5.1 (F.6.5.1)

    Step 2: Compute (cx′, cy′)
     求椭圆弧参数转换算法, Conversion from endpoint to center parameterizationEquation F.6.5.2 (F.6.5.2)

    where the + sign is chosen if fA ≠ fS, and the − sign is chosen if fA = fS.

    Step 3: Compute (cx, cy) from (cx′, cy′)
     求椭圆弧参数转换算法, Conversion from endpoint to center parameterizationEquation F.6.5.3 (F.6.5.3)

    Step 4: Compute θ1 and Δθ

    In general, the angle between two vectors (ux, uy) and (vx, vy) can be computed as
     求椭圆弧参数转换算法, Conversion from endpoint to center parameterizationEquation F.6.5.4 (F.6.5.4)

    where the ± sign appearing here is the sign of ux vy − uy vx.

    This angle function can be used to express θ1 and Δθ as follows:
     求椭圆弧参数转换算法, Conversion from endpoint to center parameterizationEquation F.6.5.5 (F.6.5.5)
     求椭圆弧参数转换算法, Conversion from endpoint to center parameterizationEquation F.6.5.6 (F.6.5.6)

    where θ1 is fixed in the range −360° < Δθ < 360° such that:

    if fS = 0, then Δθ < 0,

    else if fS = 1, then Δθ > 0.

    In other words, if fS = 0 and the right side of (F.6.5.6) is greater than 0, then subtract 360°, whereas if fS = 1 and the right side of (F.6.5.6) is less than 0, then add 360°. In all other cases leave it as is.

4 个解决方案

#1


楼主,既然你教会我一个公式,我就帮你写一个代码,不过这份代码未经调试,需要你自己验证一下。


/**
svg里面绘制椭圆弧的参数是这样的:x1 y1 x2 y2 fA fS rx ry φ
分别代表的含义是:
(x1 y1)圆弧路径起点
(x2 y2)圆弧路径终点
fA 标记是否大弧段
fS 标记是否顺时针绘制
rx 椭圆弧的X半轴长度
ry 椭圆弧的Y半轴长度
φ 椭圆弧X轴方向的旋转角度

http://topic.csdn.net/u/20120511/17/d278e925-75f0-4325-8926-b812f2d95b23.html?85757
http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
*/


#include <stdio.h>
#include <math.h>

double  radian( double ux, double uy, double vx, double vy ) {
double  dot = ux * vx + uy * vy;
double  mod = sqrt( ( ux * ux + uy * uy ) * ( vx * vx + vy * vy ) );
double  rad = acos( dot / mod );
if( ux * vy - uy * vx < 0.0 ) rad = -rad;
return  rad;
}

int  conversion_from_endpoint_to_center_parameterization(
double x1, double y1, double x2, double y2,
bool fA, bool fS,
double rx, double ry, double phi,
double &cx, double &cy, double &theta1, double &delta_theta ) {

if( rx == 0.0 || ry == 0.0 ) return -1;  // 不是椭圆

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

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

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

// F6.5.2
double  cx_ = coe * rxy1_ / ry;
double  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;

double  xcr1 = ( x1_ - cx_ ) / rx;
double  xcr2 = ( x1_ + cx_ ) / rx;
double  ycr1 = ( y1_ - cy_ ) / ry;
double  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 );
double  PIx2 = M_PI * 2.0;
while( delta_theta > PIx2 ) delta_theta -= PIx2;
while( delta_theta < 0.0 ) delta_theta += PIx2;
if( fS == false ) delta_theta -= PIx2;

return 0;
}

#2


头文件那里需要加一句,否则编译器不认得M_PI


#define _USE_MATH_DEFINES
#include <math.h>

#3


谢谢gogdizzy,我按你的试试去

#4


gogdizzy的代码,验证可行,结帖给分。

#1


楼主,既然你教会我一个公式,我就帮你写一个代码,不过这份代码未经调试,需要你自己验证一下。


/**
svg里面绘制椭圆弧的参数是这样的:x1 y1 x2 y2 fA fS rx ry φ
分别代表的含义是:
(x1 y1)圆弧路径起点
(x2 y2)圆弧路径终点
fA 标记是否大弧段
fS 标记是否顺时针绘制
rx 椭圆弧的X半轴长度
ry 椭圆弧的Y半轴长度
φ 椭圆弧X轴方向的旋转角度

http://topic.csdn.net/u/20120511/17/d278e925-75f0-4325-8926-b812f2d95b23.html?85757
http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
*/


#include <stdio.h>
#include <math.h>

double  radian( double ux, double uy, double vx, double vy ) {
double  dot = ux * vx + uy * vy;
double  mod = sqrt( ( ux * ux + uy * uy ) * ( vx * vx + vy * vy ) );
double  rad = acos( dot / mod );
if( ux * vy - uy * vx < 0.0 ) rad = -rad;
return  rad;
}

int  conversion_from_endpoint_to_center_parameterization(
double x1, double y1, double x2, double y2,
bool fA, bool fS,
double rx, double ry, double phi,
double &cx, double &cy, double &theta1, double &delta_theta ) {

if( rx == 0.0 || ry == 0.0 ) return -1;  // 不是椭圆

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

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

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

// F6.5.2
double  cx_ = coe * rxy1_ / ry;
double  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;

double  xcr1 = ( x1_ - cx_ ) / rx;
double  xcr2 = ( x1_ + cx_ ) / rx;
double  ycr1 = ( y1_ - cy_ ) / ry;
double  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 );
double  PIx2 = M_PI * 2.0;
while( delta_theta > PIx2 ) delta_theta -= PIx2;
while( delta_theta < 0.0 ) delta_theta += PIx2;
if( fS == false ) delta_theta -= PIx2;

return 0;
}

#2


头文件那里需要加一句,否则编译器不认得M_PI


#define _USE_MATH_DEFINES
#include <math.h>

#3


谢谢gogdizzy,我按你的试试去

#4


gogdizzy的代码,验证可行,结帖给分。