首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将svg弧转换为线条

将svg弧转换为线条
EN

Stack Overflow用户
提问于 2017-01-08 21:11:38
回答 2查看 1.2K关注 0票数 3

我正在尝试将SVG弧转换成一系列的线段。背景是,我想使用(reportlab)[http://www.reportlab.com/]绘制一个弧形。

svg给出了这些参数(根据这里)。

rx,ry,x轴旋转,大弧旗,扫旗,dx,dy

现在我需要确定沿着这条弧线的线。但我不明白如何才能把它转换成更实用的几何图形。

如何确定椭圆弧的中心及其旋转?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-09 09:17:37

SVG椭圆弧非常棘手,我花了一段时间才实现它(甚至遵循SVG规范)。我在C++以这样的方式结束了

代码语言:javascript
复制
//---------------------------------------------------------------------------
class svg_usek  // virtual class for svg_line types
    {
public:
    int pat;                // svg::pat[] index
    virtual void reset(){};
    virtual double getl (double mx,double my){ return 1.0; };
    virtual double getdt(double dl,double mx,double my){ return 0.1; };
    virtual void getpnt(double &x,double &y,double t){};
    virtual void compute(){};
    virtual void getcfg(AnsiString &nam,AnsiString &dtp,AnsiString &val){};
    virtual void setcfg(AnsiString &nam,AnsiString &dtp,AnsiString &val,int &an,int &ad,int &av){};
    };
//---------------------------------------------------------------------------
class svg_ela:public svg_usek       // sweep = 0 arc goes from line p0->p1 CW
    {                               // sweep = 1 arc goes from line p0->p1 CCW
public:                             // larc is unused if |da|=PI
    double x0,y0,x1,y1,a,b,alfa; int sweep,larc;
    double sx,sy,a0,a1,da,ang;      // sx,sy rotated center by ang
    double cx,cy;                   // real center
    void reset() { x0=0; y0=0; x1=0; y1=0; a=0; b=0; alfa=0; sweep=false; larc=false; compute(); }
    double getl (double mx,double my);
//  double getdt(double dl,double mx,double my);
    double getdt(double dl,double mx,double my) { int n; double dt; dt=divide(dl,getl(mx,my)); n=floor(divide(1.0,dt)); if (n<1) n=1; return divide(1.0,n); }
    void getpnt(double &x,double &y,double t);
    void compute();
    void getcfg(AnsiString &nam,AnsiString &dtp,AnsiString &val);
    void setcfg(AnsiString &nam,AnsiString &dtp,AnsiString &val,int &an,int &ad,int &av);
    svg_ela()       {}
    svg_ela(svg_ela& a) { *this=a; }
    ~svg_ela()  {}
    svg_ela* operator = (const svg_ela *a) { *this=*a; return this; }
    //svg_ela* operator = (const svg_ela &a) { ...copy... return this; }
    };
//---------------------------------------------------------------------------
void svg_ela::getpnt(double &x,double &y,double t)
    {
    double c,s,xx,yy;
    t=a0+(da*t);
    xx=sx+a*cos(t);
    yy=sy+b*sin(t);
    c=cos(-ang);
    s=sin(-ang);
    x=xx*c-yy*s;
    y=xx*s+yy*c;
    }
//---------------------------------------------------------------------------
void svg_ela::compute()
    {
    double  ax,ay,bx,by;            // body
    double  vx,vy,l,db;
    int     _sweep;
    double  c,s,e;

    ang=pi-alfa;
    _sweep=sweep;
    if (larc) _sweep=!_sweep;

    e=divide(a,b);
    c=cos(ang);
    s=sin(ang);
    ax=x0*c-y0*s;
    ay=x0*s+y0*c;
    bx=x1*c-y1*s;
    by=x1*s+y1*c;

    ay*=e;                  // transform to circle
    by*=e;

    sx=0.5*(ax+bx);         // mid point between A,B
    sy=0.5*(ay+by);
    vx=(ay-by);
    vy=(bx-ax);
    l=divide(a*a,(vx*vx)+(vy*vy))-0.25;
    if (l<0) l=0;
    l=sqrt(l);
    vx*=l;
    vy*=l;

    if (_sweep)
        {
        sx+=vx;
        sy+=vy;
        }
    else{
        sx-=vx;
        sy-=vy;
        }

    a0=atanxy(ax-sx,ay-sy);
    a1=atanxy(bx-sx,by-sy);
//  ay=divide(ay,e);
//  by=divide(by,e);
    sy=divide(sy,e);


    da=a1-a0;
    if (fabs(fabs(da)-pi)<=_acc_zero_ang)       // half arc is without larc and sweep is not working instead change a0,a1
        {
        db=(0.5*(a0+a1))-atanxy(bx-ax,by-ay);
        while (db<-pi) db+=pi2;     // db<0 CCW ... sweep=1
        while (db>+pi) db-=pi2;     // db>0  CW ... sweep=0
        _sweep=0;
        if ((db<0.0)&&(!sweep)) _sweep=1;
        if ((db>0.0)&&( sweep)) _sweep=1;
        if (_sweep)
            {
//          a=0; b=0;
            if (da>=0.0) a1-=pi2;
            if (da< 0.0) a0-=pi2;
            }
        }
    else if (larc)              // big arc
        {
        if ((da< pi)&&(da>=0.0)) a1-=pi2;
        if ((da>-pi)&&(da< 0.0)) a0-=pi2;
        }
    else{                       // small arc
        if (da>+pi) a1-=pi2;
        if (da<-pi) a0-=pi2;
        }
    da=a1-a0;

    // realny stred
    c=cos(+ang);
    s=sin(+ang);
    cx=sx*c-sy*s;
    cy=sx*s+sy*c;
    }
//---------------------------------------------------------------------------

atanxy(x,y)atan2(y,x)相同。您可以忽略类svg_usek。使用svg_ela很简单,首先将SVG参数提供给它:

  • x0,y0是起点(来自以前的<path>元素)
  • x1,y1是端点(x0+dx,y0+dy)
  • a,b和你一样rx,ry
  • alfa旋转角度[rad]所以你需要转换度.
  • sweep,larc和你一样。

然后调用svg_ela::compute();,它将计算插值所需的所有变量。当完成此初始化时,要从弧中获取任何点,只需调用svg_ela::getpnt(x,y,t);,其中x,y是返回的坐标,t=<0,1>是输入参数。其他的方法对你来说都不重要。若要呈现您的ARC,只需执行以下操作:

代码语言:javascript
复制
svg_ela arc; // your initialized arc here
int e; double x,y,t;
arc.getpnt(x,y,0.0);
Canvas->MoveTo(x,y);
for (e=1,t=0.0;e;t+=0.02)
 {
 if (t>=1.0) { t=1.0; e=0; }
 arc.getpnt(x,y,t);
 Canvas->LineTo(x,y);
 }

不要忘记,、SVG、<g><path>可以有转换矩阵,因此您应该在每个svg_ela::getpnt(x,y,t)调用之后应用它们。

如果您对这些东西的工作方式感兴趣,那么简单地说,compute()

  1. 旋转空间,因此椭圆半轴是对轴的。
  2. 缩放空间,使椭圆变成圆形。
  3. 计算圆的中心点 中心位于与直线(x0,y0),(x1,y1)垂直的直线上,也位于其中点。距离由Pytagoras和从sweeplarc组合的方向计算。
  4. 缩回椭圆
  5. 向后旋转

现在我们有了实际的中心位置,所以也计算了相对于它的实际端点角。现在,对于椭圆上的每一点,用椭圆的标准参数方程来计算就足够了,并且旋转到期望的位置,这就是getpnt(x,y,t)所做的。

希望能帮上点忙。

以下是相关的质量保证:

通过一些图片解释SVG弧背后的数学(使用与这里相同的变量名)

票数 6
EN

Stack Overflow用户

发布于 2021-04-11 21:10:54

对于我的Java应用程序,我需要将路径弧转换为行。我使用了上述代码并将其转换为Java类,并执行了一些清理。

代码语言:javascript
复制
package de.berndbock.tinysvg.helper;

/**
 * Breaks down SVG arcs into line segments.
 * 
 * @author Bernd Bock <chef@bernd-bock.de>
 */
public class ArcSegmenter {
    
    private static final double PI2 = Math.PI * 2;
    private static final double ACC_ZERO_ANG = 0.000001 * Math.PI / 180.0;
    
    private final double x0;
    private final double y0;
    private final double x1;
    private final double y1;
    private final double a;
    private final double b;
    private final double alfa;
    private final boolean sweep;
    private final boolean larc;
    private double sx, sy, a0, a1, da, ang;  // sx, sy rotated center by ang
//    private double cx, cy;                   // real center
    
    public ArcSegmenter(double x0, double y0, double x1, double y1 , double a, double b, double alfa, int sweep, int larc) {
        this.x0 = x0;
        this.y0 = y0;
        this.x1 = x1;
        this.y1 = y1;
        this.a = a;
        this.b = b;
        this.alfa = alfa;
        this.sweep = sweep != 0;
        this.larc = larc != 0;
        compute();
    }
    
    private void compute() {
        double  ax, ay, bx, by;            // body
        double  vx, vy, l, db;
        boolean _sweep;
        double  c, s, e;

        ang = Math.PI - alfa;
        _sweep = sweep;
        if (larc) {
            _sweep = !_sweep;
        }

        e = a / b;
        c = Math.cos(ang);
        s = Math.sin(ang);
        ax = x0 * c - y0 * s;
        ay = x0 * s + y0 * c;
        bx = x1 * c - y1 * s;
        by = x1 * s + y1 * c;

        ay *= e;                  // transform to circle
        by *= e;

        sx = 0.5 * (ax + bx);     // mid point between A,B
        sy = 0.5 * (ay + by);
        vx = (ay - by);
        vy = (bx - ax);
        l = a * a / (vx * vx + vy * vy) - 0.25;
        if (l < 0) {
            l = 0;
        }
        l = Math.sqrt(l);
        vx *= l;
        vy *= l;

        if (_sweep) {
            sx += vx;
            sy += vy;
        }
        else {
            sx -= vx;
            sy -= vy;
        }

        a0 = Math.atan2(ay - sy, ax - sx);
        a1 = Math.atan2(by - sy, bx - sx);
        sy = sy / e;

        da = a1 - a0;
        if (Math.abs(Math.abs(da) - Math.PI) <= ACC_ZERO_ANG) {     // half arc is without larc and sweep is not working instead change a0,a1
            db = (0.5 * (a0 + a1)) - Math.atan2(by - ay, bx - ax);
            while (db < -Math.PI) {
                db += PI2;     // db<0 CCW ... sweep=1
            }
            while (db >  Math.PI) {
                db -= PI2;     // db>0  CW ... sweep=0
            }
            _sweep = false;
            if ((db < 0.0) && (!sweep)) {
                _sweep = true;
            }
            if ((db > 0.0) && ( sweep)) {
                _sweep = true;
            }
            if (_sweep) {
                if (da >= 0.0) {
                    a1 -= PI2;
                }
                if (da <  0.0) {
                    a0 -= PI2;
                }
            }
        }
        else if (larc) {            // big arc
            if ((da <  Math.PI) && (da >= 0.0)) {
                a1 -= PI2;
            }
            if ((da > -Math.PI) && (da <  0.0)) {
                a0 -= PI2;
            }
        }
        else {                      // small arc
            if (da >  Math.PI) {
                a1 -= PI2;
            }
            if (da < -Math.PI) {
                a0 -= PI2;
            }
        }
        da = a1 - a0;

// center point calculation:
//        c = Math.cos(ang);
//        s = Math.sin(ang);
//        cx = sx * c - sy * s;
//        cy = sx * s + sy * c;
    }
    
    public Point getpnt(double t) {
        Point result = new Point();
        double c, s, x, y;
        
        t = a0 + da * t;
        x = sx + a * Math.cos(t);
        y = sy + b * Math.sin(t);
        c = Math.cos(-ang);
        s = Math.sin(-ang);
        result.x = x * c - y * s;
        result.y = x * s + y * c;
        
        return result;
    }
    
//    public Point getCenterPoint() {
//        return new Point(cx, cy);
//    }
}

如果需要中心点,则取消相应的行注释。示例代码可以让您了解使用情况:

代码语言:javascript
复制
ArcSegmenter segmenter = new ArcSegmenter(currentPoint.x, currentPoint.y, endPoint.x, endPoint.y, rx, ry, phi, sf, lf);
Point p1, p2;
p1 = segmenter.getpnt(0.0);
Line line;

for (double t = increment; t < 1.000001f; t += increment) {
    p2 = segmenter.getpnt(t);
    line = new Line(null, parent, p1.x, p1.y, p2.x, p2.y);
    elements.add(line);
    p1 = p2;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41537950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档