使用贝塞尔曲线进行插值 一种非常简单的平滑多边形的方法

原文Interpolation with Bezier Curves A very simple method of smoothing polygons


Initially, there was a question in comp.graphic.algorithms how to interpolate a polygon with a curve in such a way that the resulting curve would be smooth and hit all its vertices. Gernot Hoffmannsuggested to use a well-known B-Spline interpolation. Here is his original article. B-Spline works good and it behaves like an elastic ruler fixed in the polygon vertices.


 

 

But I had a gut feeling that there must be a simpler method. For example, approximation with cubic Bezier curves. A Bezier curve has two anchor points (begin and end) and two control ones (CP) that determine its shape. More information about Bezier curves can be found using any search engine, for example, on Paul Bourke‘s excellent site. Our anchor points are given, they are pair of vertices of the polygon. The question was, how to calculate the control points. I ran Xara X and drew this picture. It was pretty easy and I decided to try to calculate their coordinates. It was obvious that the control points of two adjacent edges plus the vertex between them should form one straight line. Only in this case the two adjacent curves will be connected smoothly. So, the two CP should be the a reflection of each other, but… not quite. Reflection assumes equal distances from the central point. For our case it‘s not correct. First, I tried to calculate a bisectrix between two edges and then take points on the perpendicular to it. But as shown in the picture, the CP not always lie on the perpendicular to the bisectrix.

 

Finally, I found a very simple method that does not require any complicated math. First, we take the polygon and calculate the middle points Ai of its edges.

 

Here we have line segments Ci that connect two points Ai of the adjacent segments. Then, we should calculate points Bias shown in this picture.

 

The third step is final. We simply move the line segments Ci in such a way that their points Bi coincide with the respective vertices. That‘s it, we calculated the control points for our Bezier curve and the result looks good.

 

One little improvement. Since we have a straight line that determines the place of our control points, we can move them as we want, changing the shape of the resulting curve. I used a simple coefficient K that moves the points along the line relatively to the initial distance between vertices and control points. The closer the control points to the vertices are the sharper figure will be obtained.

 

Below is the result of rendering a popular in SVG lion in its original form and with Bezier interpolation with K=1.0


 

 

And the enlarged ones.


 

 

The method works quite well with self-intersecting polygons. The examples below show that the result is pretty interesting.

 
 
 

This method is pure heuristic and empiric. It probably gives a wrong result from the point of view of strict mathematical modeling. But in practice the result is good enough and it requires absolute minimum of calculations. Below is the source code that has been used to generate the lions shown above. It‘s not optimal and just an illustration. It calculates some variables twice, while in real programs we can store and reuse them in the consecutive steps.

    // Assume we need to calculate the control
    // points between (x1,y1) and (x2,y2).
    // Then x0,y0 - the previous vertex,
    //      x3,y3 - the next one.

    double xc1 = (x0 + x1) / 2.0;
    double yc1 = (y0 + y1) / 2.0;
    double xc2 = (x1 + x2) / 2.0;
    double yc2 = (y1 + y2) / 2.0;
    double xc3 = (x2 + x3) / 2.0;
    double yc3 = (y2 + y3) / 2.0;

    double len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
    double len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
    double len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));

    double k1 = len1 / (len1 + len2);
    double k2 = len2 / (len2 + len3);

    double xm1 = xc1 + (xc2 - xc1) * k1;
    double ym1 = yc1 + (yc2 - yc1) * k1;

    double xm2 = xc2 + (xc3 - xc2) * k2;
    double ym2 = yc2 + (yc3 - yc2) * k2;

    // Resulting control points. Here smooth_value is mentioned
    // above coefficient K whose value should be in range [0...1].
    ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
    ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;

    ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
    ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;

And the source code of an approximation with a cubic Bezier curve.

// Number of intermediate points between two source ones,
// Actually, this value should be calculated in some way,
// Obviously, depending on the real length of the curve.
// But I don‘t know any elegant and fast solution for this
// problem.
#define NUM_STEPS 20

void curve4(Polygon* p,
            double x1, double y1,   //Anchor1
            double x2, double y2,   //Control1
            double x3, double y3,   //Control2
            double x4, double y4)   //Anchor2
{
    double dx1 = x2 - x1;
    double dy1 = y2 - y1;
    double dx2 = x3 - x2;
    double dy2 = y3 - y2;
    double dx3 = x4 - x3;
    double dy3 = y4 - y3;

    double subdiv_step  = 1.0 / (NUM_STEPS + 1);
    double subdiv_step2 = subdiv_step*subdiv_step;
    double subdiv_step3 = subdiv_step*subdiv_step*subdiv_step;

    double pre1 = 3.0 * subdiv_step;
    double pre2 = 3.0 * subdiv_step2;
    double pre4 = 6.0 * subdiv_step2;
    double pre5 = 6.0 * subdiv_step3;

    double tmp1x = x1 - x2 * 2.0 + x3;
    double tmp1y = y1 - y2 * 2.0 + y3;

    double tmp2x = (x2 - x3)*3.0 - x1 + x4;
    double tmp2y = (y2 - y3)*3.0 - y1 + y4;

    double fx = x1;
    double fy = y1;

    double dfx = (x2 - x1)*pre1 + tmp1x*pre2 + tmp2x*subdiv_step3;
    double dfy = (y2 - y1)*pre1 + tmp1y*pre2 + tmp2y*subdiv_step3;

    double ddfx = tmp1x*pre4 + tmp2x*pre5;
    double ddfy = tmp1y*pre4 + tmp2y*pre5;

    double dddfx = tmp2x*pre5;
    double dddfy = tmp2y*pre5;

    int step = NUM_STEPS;

    // Suppose, we have some abstract object Polygon which
    // has method AddVertex(x, y), similar to LineTo in
    // many graphical APIs.
    // Note, that the loop has only operation add!
    while(step--)
    {
        fx   += dfx;
        fy   += dfy;
        dfx  += ddfx;
        dfy  += ddfy;
        ddfx += dddfx;
        ddfy += dddfy;
        p->AddVertex(fx, fy);
    }
    p->AddVertex(x4, y4); // Last step must go exactly to x4, y4
}

You can download a working application for Windows that renders the lion, rotates and scales it, and generates random polygons. Interpolation with Bezier curves  (bezier_interpolation.zip). Press left mouse button and drag to rotate and scale the image around the center point. Press right mouse button and drag left-right to change the coefficient of smoothing (K). Value K=1 is about 100 pixels from the left border of the window. Each left double-click generates a random polygon. You can also rotate and scale it, and change K.

 
Copyright © 2002-2006 Maxim Shemanarev
Web Design and Programming Maxim Shemanarev

原文地址:https://www.cnblogs.com/lonelyxmas/p/9293707.html

时间: 2024-10-10 08:25:06

使用贝塞尔曲线进行插值 一种非常简单的平滑多边形的方法的相关文章

贝塞尔曲线的使用

什么是贝塞尔曲线 它主要用在Andorid中某些自定义VIew的时候需要绘制某些曲线.它只要有些名词介绍: 数据点:通常指一条路径的起始点和终止点 控制点:控制点决定可一条路径的弯曲轨迹,根据控制的点的个数,贝塞尔曲线被分为一阶贝塞尔曲线(0个控制点).二阶贝塞尔曲线(1个控制点).三阶贝塞尔曲线(2个控制点) 在平时开发中主要掌握二阶和三阶贝塞尔曲线 二阶贝塞尔曲线 由上图看,P0是起点,P2是终点.P1是控制点,t是一个系数,表示从0-1的变化过程,红色的线就是最终画出的曲线.其中主要是用到

n阶贝塞尔曲线绘制(C/C#)

原文:n阶贝塞尔曲线绘制(C/C#) 贝塞尔是很经典的东西,轮子应该有很多的.求n阶贝塞尔曲线用到了?德卡斯特里奥算法(De Casteljau's Algorithm) 需要拷贝代码请直接使用本文最后的例程,文章前面的大部分代码都不是最佳实践,是在编程过程中的摸索(走过的弯路),不过这些示范对笔者今后写算法启发很大. 要完成的功能是根据起点,终点和控制点,绘制n阶贝塞尔曲线 首先看n阶贝塞尔曲线的公式 公式中用了组合数,大数组合数计算也有算法: 简言之就是把 ?大数乘以大数除以大数 ?这个过程

贝塞尔曲线实现的购物车添加商品动画效果

效果图如下: 1.activity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rly_bezier_curve_shopping_cart" android:layout_w

把商品添加到购物车的动画效果(贝塞尔曲线)

如图: 参考: Android补间动画,属性动画实现购物车添加动画 思路: 确定动画的起终点 在起终点之间使用二次贝塞尔曲线填充起终点之间的点的轨迹 设置属性动画,ValueAnimator插值器,获取中间点的坐标 将执行动画的控件的x.y坐标设为上面得到的中间点坐标 开启属性动画 当动画结束时的操作 难点: PathMeasure的使用 - getLength() - boolean getPosTan(float distance, float[] pos, float[] tan) 的理解

html5 canvas绘图-贝塞尔曲线

贝塞尔曲线(ezier curve)最迟是由法国物理学家与数学家paul de Casteljau发明的.它的广泛运用则要归功于法国工程师皮埃尔 贝塞尔 贝塞尔曲线期初被用在汽车车身的设计上.现在则多用于计算机图形系统中.例如Adobe Illustrator/Apple的Cocoa框架以及在Html5的canvas. 贝塞尔曲线分为两种:平方(quadratic)贝塞尔曲线及立方(cubic)贝塞尔曲线.平方贝塞尔曲线是一种二次曲线(second degree curve),意思就是说,它们是

曲线之美 --贝塞尔曲线

原文:http://blog.csdn.net/killwd/article/details/1460478 贝塞尔曲线   维基百科 http://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A 在图形图像编程时,我们常常需要根据一系列已知点坐标来确 定一条光滑曲线.其中有些曲线需要严格地通过所有的已知点,而有些曲线却不一定需要.在后者中,比较有代表性的一类曲线是贝塞尔曲线(Bézier Splines). 网友们可能注意到

贝塞尔曲线实现购物车飞入效果

代码地址如下:http://www.demodashi.com/demo/12618.html 前言 做了一个模仿添加物品飞入购物车效果的例子,下面来讲讲它的简单使用 将涉及到以下内容: 工具类的使用 项目结构图与效果图 程序设计与实现 一. 工具类设计 工具类比较多代码,这里就不每个都贴出来了,如下截图为工具类 二. 工具类的使用 飞入购物车效果我封装成了一个工具类FlyAnimtor,下面讲讲它的使用. 如果你想使用飞入效果,你可以这样写: FlyAnimtor.getInstance().

OpenGL 实践之贝塞尔曲线绘制

说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图. 以下两个是比较经典的动图了. 二阶贝塞尔曲线: 三阶贝塞尔曲线: 由于在工作中经常要和贝塞尔曲线打交道,所以简单说一下自己的理解: 现在假设我们要在坐标系中绘制一条直线,直线的方程很简单,就是 y=x ,很容易得到下图: 现在我们限制一下 x 的取值范围为 0~1 的闭区间,那么可以得出 y 的取值范围也是 0~1. 而在 0~1 的区间范围内,x 能取的数有多少个呢?答案当然是无数个了. 同理,y 的取值

Android日常学习:OpenGL 实践之贝塞尔曲线绘制

说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图. 以下两个是比较经典的动图了. 二阶贝塞尔曲线: 三阶贝塞尔曲线: 由于在工作中经常要和贝塞尔曲线打交道,所以简单说一下自己的理解: 现在假设我们要在坐标系中绘制一条直线,直线的方程很简单,就是 y=x ,很容易得到下图: 现在我们限制一下 x 的取值范围为 0~1 的闭区间,那么可以得出 y 的取值范围也是 0~1. 而在 0~1 的区间范围内,x 能取的数有多少个呢?答案当然是无数个了. 同理,y 的取值