这篇文章里的代码的C#版本 (穿过已知点画平滑曲线(3次贝塞尔曲线)

来自:https://blog.csdn.net/microchenhong/article/details/6316332

真正的原文:https://www.cnblogs.com/muxue/archive/2010/06/23/1763886.html

原文的原文:http://agg.sourceforge.net/antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION

没时间研究,先翻译过来

Point类用的是wpf里的Point,就是里面有double类型的X,Y,没有其他依赖

void createCurve(Point[] originPoint, int originCount, List<Point> curvePoint)
        {
            //控制点收缩系数 ,经调试0.6较好
            double scale = 0.6;
            Point[] midpoints = new Point[originCount];
            //生成中点       
            for (int i = 0; i < originCount; i++)
            {
                int nexti = (i + 1) % originCount;
                midpoints[i].X = (originPoint[i].X + originPoint[nexti].X) / 2.0;
                midpoints[i].Y = (originPoint[i].Y + originPoint[nexti].Y) / 2.0;
            }

            //平移中点  
            Point[] extrapoints = new Point[2 * originCount];
            for (int i = 0; i < originCount; i++)
            {
                int nexti = (i + 1) % originCount;
                int backi = (i + originCount - 1) % originCount;
                Point midinmid = new Point();
                midinmid.X = (midpoints[i].X + midpoints[backi].X) / 2.0;
                midinmid.Y = (midpoints[i].Y + midpoints[backi].Y) / 2.0;
                double offsetx = originPoint[i].X - midinmid.X;
                double offsety = originPoint[i].Y - midinmid.Y;
                int extraindex = 2 * i;
                extrapoints[extraindex].X = midpoints[backi].X + offsetx;
                extrapoints[extraindex].Y = midpoints[backi].Y + offsety;
                //朝 originPoint[i]方向收缩   
                double addx = (extrapoints[extraindex].X - originPoint[i].X) * scale;
                double addy = (extrapoints[extraindex].Y - originPoint[i].Y) * scale;
                extrapoints[extraindex].X = originPoint[i].X + addx;
                extrapoints[extraindex].Y = originPoint[i].Y + addy;

                int extranexti = (extraindex + 1) % (2 * originCount);
                extrapoints[extranexti].X = midpoints[i].X + offsetx;
                extrapoints[extranexti].Y = midpoints[i].Y + offsety;
                //朝 originPoint[i]方向收缩   
                addx = (extrapoints[extranexti].X - originPoint[i].X) * scale;
                addy = (extrapoints[extranexti].Y - originPoint[i].Y) * scale;
                extrapoints[extranexti].X = originPoint[i].X + addx;
                extrapoints[extranexti].Y = originPoint[i].Y + addy;

            }

            Point[] controlPoint = new Point[4];
            //生成4控制点,产生贝塞尔曲线  
            for (int i = 0; i < originCount; i++)
            {
                controlPoint[0] = originPoint[i];
                int extraindex = 2 * i;
                controlPoint[1] = extrapoints[extraindex + 1];
                int extranexti = (extraindex + 2) % (2 * originCount);
                controlPoint[2] = extrapoints[extranexti];
                int nexti = (i + 1) % originCount;
                controlPoint[3] = originPoint[nexti];
                double u = 1;
                while (u >= 0)
                {
                    double px = bezier3funcX(u, controlPoint);
                    double py = bezier3funcY(u, controlPoint);
                    //u的步长决定曲线的疏密  
                    u -= 0.005;
                    Point tempP = new Point(px, py);
                    //存入曲线点   
                    curvePoint.Add(tempP);
                }
            }
        }
        //三次贝塞尔曲线  
        double bezier3funcX(double uu, Point[] controlP)
        {
            double part0 = controlP[0].X * uu * uu * uu;
            double part1 = 3 * controlP[1].X * uu * uu * (1 - uu);
            double part2 = 3 * controlP[2].X * uu * (1 - uu) * (1 - uu);
            double part3 = controlP[3].X * (1 - uu) * (1 - uu) * (1 - uu);
            return part0 + part1 + part2 + part3;
        }
        double bezier3funcY(double uu, Point[] controlP)
        {
            double part0 = controlP[0].Y * uu * uu * uu;
            double part1 = 3 * controlP[1].Y * uu * uu * (1 - uu);
            double part2 = 3 * controlP[2].Y * uu * (1 - uu) * (1 - uu);
            double part3 = controlP[3].Y * (1 - uu) * (1 - uu) * (1 - uu);
            return part0 + part1 + part2 + part3;
        }

 public void GetControlPoint(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double smooth_value)
        {

            // 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 = Math.Sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
            double len2 = Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
            double len3 = Math.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].
            ///两个控制点
            double ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
            double ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;

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

void curve4(List<Point> p,
                    double x1, double y1,   //Anchor1
                    double x2, double y2,   //Control1
                    double x3, double y3,   //Control2
                    double x4, double y4)   //Anchor2
        {
            int step = 20;

            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 / (step + 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;



            // 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 > 0)
            {
                step--;
                fx += dfx;
                fy += dfy;
                dfx += ddfx;
                dfy += ddfy;
                ddfx += dddfx;
                ddfy += dddfy;
                p.Add(new Point(fx, fy));
            }
            p.Add(new Point(x4, y4)); // Last step must go exactly to x4, y4
        }

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值