精华内容
下载资源
问答
  • 2018-11-22 11:25:05
    #include <iostream> 
    #include <stdio.h>
    #include <math.h>
    
    using namespace std;
    
    typedef struct point{	
    	float x;
    	float y;
    } Point;
    
    
    long long * fun(int n){
    	long long *res = new long long[10];
    	res[0] = 1;
    	res[1] = 1;	
    	for(int i = 2; i<=n; ++i){
    		res[i] = res[i-1] * i;
    	}
    	
    	return res;
    }
    void decastljao(Point *res, Point *al, float span, int al_size){
    	
    	int n = al_size - 1;	
    	if(n < 1){
    		return ;
    	}
    	
    	int steps = (int) (1.0 / span);
    	
    	
    	long long * NA = fun(n);
    //	for(int i = 0; i<n; ++i){
    //		printf("%lld \n", NA[i]);
    //	}
    	
    	
    	//分别求曲线上的每一个点,按顺序
    	
    	
    	for(int i=0; i<= steps; ++i){		
    		float t = i * span;
    		printf("t = %f \t %f\n", t, span);		
    		if(t>1){
    			t = 1;			
    		}
    		
    		float xf = 0;
    		float yf = 0;
    		
    		float * tka = new float[n+1];
    		float * otka = new float[n+1];		
    		for(int j=0; j<=n; ++j){
    			tka[j] = pow(t, j);
    			otka[j] = pow(1.0 - t, j);
    		}
    		
    		for(int k = 0; k<=n; ++k){	
    			float xs = (NA[n] / (NA[k] * NA[n-k])) * tka[k] * otka[n-k]; //这是公式,死记,曲线上的每一个点,和所有控制点有关(NA),还有分段有关(tka, otka); 
    			xf += al[k].x * xs;
    			yf += al[k].y * xs;
    		}
    		
    		res[i].x = xf;
    		res[i].y = yf;
    		
    		printf("temp xf yf = %8.5f : %8.5f\n", xf, yf);
    		printf("\n");
    	} 
    		
    }
    
    
    int main(){
    	Point temp;
    	Point al[10];
    	int al_size = 3;
    	float temp_x[] = {1.0, 2.0, 3,0};
    	float temp_y[] = {1.0, 3.0, 1.0};
    	for(int i=0; i<al_size; ++i){
    		al[i].x = temp_x[i];
    		al[i].y = temp_y[i];
    	}
    	
    	Point *res = new Point[10];
    	float span = 1.0 / 8;	//分段数,每一段的比重 
    	
    	decastljao(res, al, span, al_size);
    	
    	return 0;
    }
    

     

    更多相关内容
  • /** * 绘制四阶或更高阶贝塞尔曲线,使用德卡斯特里奥算法(贝塞尔公式)实现 */ public class BezierView2 extends View { //多控制点【第一个点和最后一个点则为开始与结束点】 private ArrayList controlPoints ...

    在上一次android高级UI之Canvas综合案例操练 - cexo - 博客园对于Android UI绘制中核心的Canvas进行了相关的学习,这块的学习也中断一年多了,既然主业是Android开发,没有任何理由能停止对它的继续学习探索,所以接下来对于Android UI的学习继续。

    贝塞尔曲线基本概念:

    目标:

    对于贝塞尔曲线的绘制其实在之前QQ气泡效果剖析 - cexo - 博客园做QQ汽泡效果时已经用到过了,平常不自定义一些特殊的效果可能不一定能用到,但是!!!如果你不了解它的绘制,可能在需要它的时候你会很抓狂,因为它的使用也不是那么容易,我还记得早些年在一家公司叫我做一个电池充电过程中的水波纹效果就死活没有搞定,最后是让组里的一位大神帮忙解决了,当时的动画需求本身就比较复杂,网上也没有类似能满足要求的开源效果,我也就是对于贝塞尔曲线的绘制不了解导致做不出来,当时真的就是“书到用时方恨少”感受,所以接下来再来对它进行一个详细的了解,当作一个复习+巩固吧,最后还是以QQ汽泡的效果做为一个实战练习,效果如下:

    整个效果用过手机版的QQ应该都比较熟悉了,不过这是没有集成到列表当中,对于列表当中如何集成也请移步到在RecyclerView中集成QQ汽泡一 - cexo - 博客园进行观赏。

    那咱们这次主要学习的是怎么画“贝塞尔曲线”对吧,那对应这个QQ汽泡来说,哪里用到了呢?这里:

    看到中间的上下两个曲线了吧,它们用到了,当然这是一个二阶贝塞尔【啥叫二阶贝塞尔呢?下面会学习到】,也是最最基础的,了解了基础的画法,对于它更加复杂的画法你也比较容易上手了,好,这是一个整体的目标。

    整个学习会参考到这位大佬的简书:高级UI---LSN-7-1-贝塞尔曲线 - 简书,不过我这边会“去其糟粕,取其精华”,最终目的就是吸收成自己的。

    概念了解:

    首先要明白,对于贝塞尔曲线,它是分阶的,不同的阶数,其绘制的曲线效果也不一样,所以这里先来了解不同阶数的贝塞尔曲线的绘制情况。

    一阶贝塞尔曲线:

    先看一下效果:

    一条直线。。不是贝塞尔是用来绘制曲线的么?是的,因为对于一阶贝塞尔实际没啥用,但是对于你了解它的概念是一个基础,等于它的核心目的其实就只是由两点控制的一条直线,绘制就是从一点绘制到另一点的整个轨迹,记住这个绘制过程,因为在理解二阶贝塞尔曲线的过程中,需要使用到它。

    二阶贝塞尔曲线【重点】:

    绘制过程:

    对于二阶贝塞尔曲线来说,应该是应用最最广泛的,也是核心中的核心,对于贝塞尔曲线不是还有更加高阶复杂的曲线么?而要理解更加复杂的贝塞尔曲线,理解二阶就成为一个必须要掌握的了,只有掌握了二阶的画法,你才能更加从容的面对更加复杂的贝塞尔曲线,所以这块务必要理解透。

    先来直观的感受一下它的绘制过程:

    嗯,此图来自于csdn,看完此效果之后是不是觉得挺酷炫的?而在上面QQ汽泡效果中的那个曲线,是不是跟这个二阶曲线能联系起来?这也就是为啥在之后的贝塞尔曲线的案例应用时QQ汽泡效果使用的是二阶贝塞尔的原因了,但是你能看懂它的绘制规则么?反正我光看这动图还是一脸懵逼的,所以接下来会了解其原理,这样才能真正理解它。

    绘制原理:

    先明显对于二阶贝塞尔曲线是由三个点来进行构成的,如下:

    其中AC这两点本来是应该绘制一条直线的对吧:

    但是该直线需要受B点往下进行拖动,这个B其实就是一个控制点,正因为有这个控制点才会让本应该绘直线的最终变成了绘制曲线了,其实在我们电脑的绘制软件中也能直观的感受一下这个B点的控制点的魅力,比如我mac上用Paintbrush这个软件有一个曲线的绘制:

    我要绘制一条曲线,也是先绘制一条直线,然后再通过对直线的拖拽才完成曲线的绘制的,如下:

    所以,此时应该对于B点它的出现的意义有了直观的了解了吧,接下来重点是就来看一下这个曲线的绘制规则了,这里先把两点到控制点连接两条直线,如下:

    然后曲线的整体绘制是由AB这条一阶贝塞尔曲线来控制:

    那AC的这根曲线很显然也是由一大堆的点的连续构成的对吧,让曲线上的绘制点又是如何来确定的呢?现在整个曲线的控制是由AB这个贝塞尔曲线来控制,它是一个运动的轨迹【这一点必须要理解到位,它是不断在走的,不明白的可以看一下一阶贝塞尔曲线的那个动图】,也就是AB上走了多少个点,就会对应的生成曲线上的各个点,这里以AB上的某一个静止点进行分析,把它如何确定最终曲线上的绘制点的搞清楚了,你也就明白了整个曲线的绘制原理了,比如AB上的贝塞尔曲线走到D这个点了:

    其中这条直线上的AD跟DB就有一个比例关系了对吧,这时在BC上也取一个点E,其比例跟D点比例一样【注意关键词,比例要一样】,如下:

    好,此时将DE进行一个连线:

    接下来的绘制点就是在DE上了,那。DE上对应的绘制点是如何确定的呢?也是同样的套路,在这条直线上取一点F,要保证比例跟AD的一样,如下:

    此时F点就是最终要绘制在曲线上的一个点【注意它只是曲线上的一个点哟】,如下:

    曲线上的某个点我们已经知道怎么算出来了,我们由A-C开始启动绘制,则会算出曲线上的N个点,用PATH记录这个点进行绘制,从而y就得到了一条曲线,这条曲线就是所谓的贝塞尔曲线。这里再来回忆一下整个二阶贝塞尔曲线完整的绘制过程:

    其中t表示整个曲线的点的次数,盯着那根绿色的那根线看,是不是能感受到比例正好跟P0到P1的一阶贝塞尔走的位置比例一样,截一个静态图说明一下:

    计算公式:

    其实对于二阶贝塞尔曲线在百度上能搜到相关的公式:

    但是我看不太懂,其实有一个比较容易理解的计算公式,还是以这个图为例:

    想要找到绘制点的话只需要遵守DF:DE= AD:AB= BE:BC,那么此时F点就是绘制点,因为比例是一样的。

    三阶贝塞尔曲线:

    绘制过程:

    绘制原理:

    其原理跟二阶的一样,看一下图:

    从上图我们可以看到三阶比二阶多了一条线段,实际上表示的是最终开始点在A结束在B
    中途会往C的方法有一定的移动,然后最终到D结束,计算方式有一定的区别,先由AB BC计算出一条线,在由BC CD 计算出第二条线构建一个二阶的贝塞尔,然后进行绘制,最终绘制的点是J ,同样满足这样的公式:AE:AB= BF:BC= CG:CD= EH:EF= FI:FG= HJ:HI。

    更多阶贝塞尔曲线:

    了解了一、二、三阶贝塞尔曲线之后,接着再来感受一下更多阶的效果,让你瞬间晕眩:

    1、四阶贝塞尔曲线:

    2、五阶贝塞尔曲线:

    生成工具:

    如果想看更多阶的效果,这里推荐一个针对贝塞尔曲线学习开源的一个代码:GitHub - qingguoguo/BezierMaker: 🔥🔥🔥 通过de Casteljau算法绘制贝塞尔曲线,并计算它的切线,实现1-7阶贝塞尔曲线的形成动画。,最多支持七阶,咱们把它下下来,看一下七阶的效果:

    这对于学习贝塞尔曲线来说是一个不错的辅助工具,有兴趣的可以下下来跑一跑。

    贝塞尔曲线的基本画法:

    接下来咱们自己来体验画一画贝塞尔曲线吧,为之后的QQ消息气泡的实现打打基础。

    二阶贝塞尔曲线:

    对于Android的Path类中本身就已经提供有二、三阶曲线的API了,具体可以参考https://www.jianshu.com/p/12fcc3fedbbc:

    而我在Android7.0的源码中貌似对于三创的API是这个方法名:

    应该是有版本差异,这里就不过多纠结了,反正系统支持最多是3阶。 

    这里以绘制二阶为例,来体验一下画法。

    1、新建工程:

    这里还是基于原来学习UI时搭建的工程新建一个module:

    2、新建View:

    接下来新建一个自定义View,为曲线的绘制搭好环境:

    3、实现绘制逻辑:

    1、定义控制点:

    也就是我手指移动的位置就是一个控制点。

    2、定义开始点和结束点:

    对于三阶的贝塞尔曲线,除了控制点之外,还需要有一个开始点和结束点,这里定死一下:

    3、定义画笔:

    4、开始绘制:

    这里直接使用path.quadTo()的api既可以绘制一个二阶贝塞尔曲线,如下:

    整个代码如下:

    package com.cexo.beziermaker.test;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    /**
     * 绘制贝塞尔曲线
     */
    public class BezierView1 extends View {
    
        //曲线开始点
        private float startX, startY;
        //结束点
        private float endX, endY;
        //控制点
        private float contorlX = 200, contorlY = 60;//默认值
        private Paint paint;
        private Path path;
    
        public BezierView1(Context context) {
            this(context, null);
    
            startX = 160;
            startY = 350;
            endX = 550;
            endY = 350;
    
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(4);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.BLACK);
    
            path = new Path();
        }
    
        public BezierView1(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, -1);
        }
    
        public BezierView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            this(context, attrs, defStyleAttr, -1);
        }
    
        public BezierView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            path.reset();
            paint.setColor(Color.BLACK);
            path.moveTo(startX, startY);
            //二介曲线绘制方法
            path.quadTo(contorlX, contorlY, endX, endY);
            canvas.drawPath(path, paint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                contorlX = event.getX();
                contorlY = event.getY();
                invalidate();
            }
            return true;
        }
    } 

    5、运行:

    这里运行看一下:

    而如果想绘制三阶,也类似,使用Path的API既可,但是!!!如果三阶以上你也想绘制,怎么办?系统没有直接提供相关的API呀,所以接下来处理高阶的绘制问题。

    四阶及更高阶贝塞尔曲线:

    1、先在屏幕随机绘制5个点:

    既然是四阶,肯定是需要五个点的,一个开始点,一个结束点,还有三个控制点,所以在正式绘制曲线之前,先将准备工作做到位,这块比较简单,直接给出代码了:

    代码如下:

    package com.cexo.beziermaker.test;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PointF;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.View;
    
    import java.util.ArrayList;
    import java.util.Random;
    
    /**
     * 绘制四阶或更高阶贝塞尔曲线,使用德卡斯特里奥算法(贝塞尔公式)实现
     */
    public class BezierView2 extends View {
    
        //多控制点【第一个点和最后一个点则为开始与结束点】
        private ArrayList<PointF> controlPoints = null;
        private Paint paint, linePointPaint;
    
        public BezierView2(Context context) {
            this(context, null);
    
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(4);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.BLACK);
    
            linePointPaint = new Paint();
            linePointPaint.setAntiAlias(true);
            linePointPaint.setStrokeWidth(4);
            linePointPaint.setStyle(Paint.Style.STROKE);
            linePointPaint.setColor(Color.RED);
    
            controlPoints = new ArrayList<>();
            init();
        }
    
        private void init() {
            Random random = new Random();
            for (int i = 0; i < 5; i++) {
                int x = random.nextInt(600) + 100;
                int y = random.nextInt(600) + 100;
                PointF pointF = new PointF(x, y);
                controlPoints.add(pointF);
            }
        }
    
        public BezierView2(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, -1);
        }
    
        public BezierView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            this(context, attrs, defStyleAttr, -1);
        }
    
        public BezierView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 控制点和控制点连线
            int size = controlPoints.size();
            PointF point;
            for (int i = 0; i < size; i++) {
                point = controlPoints.get(i);
                if (i > 0) {
                    // 控制点连线
                    canvas.drawLine(controlPoints.get(i - 1).x, controlPoints.get(i - 1).y, point.x, point.y,
                            linePointPaint);
                }
                // 控制点
                canvas.drawCircle(point.x, point.y, 12, linePointPaint);
            }
        }
    }

    运行看一下效果:

    当然这个点是随机的,每次运行是不一样的。

    2、德卡斯特里奥算法(贝塞尔公式)了解:

    好,接下来的核心就是怎么来绘制贝塞尔曲线的问题了,这里则需要使用到一个比较“高深”的算法了,如小标题所示:德卡斯特里奥算法,百度一下它:

    算法的目标:

    在正式了解该算法之前,我们先从贝塞尔曲线绘制特点来分析一下,比如这个三阶贝塞尔曲线:

    是不是最终其实就是降阶来进行处理的,如下:

    而对于“德卡斯特里奥算法”而言,它的目的就是可以达到降阶的效果,其实也就是通过这个算法,最终能够算出降为一阶的绘制点:

    有了绘制点,那么将所有绘制点连接起来,不就成了一个曲线了么,这就是该算法的目的之所在,另外该算法能实现N阶贝塞尔曲线,是一个通用的算法,所以首先先明白该算法的一个目的很重要

    算法的逻辑:

    关于它的算法逻辑,说实话是有一点难理解的,反正我是在网上找了一圈,貌似说得都有点生涩,如果不理解透,你在编写代码时肯定会懵,不信,我先贴出来之后利用此算法实现贝塞尔曲线的一个代码:

    是不是在你不了解此算法的公式之前,这代码是完全理解不了的,仅仅只能把这个方法当一个工具方法来用,但是别人问你怎么实现时,可以丢一句:“代码如此,自己看吧”。

    1、先理解如何在一个线段中获得具体比例的点:【这块有点小绕,但是必须理解透】

    关于这个算法的逻辑分析可以参考这位大佬的:德卡斯特里奥算法——找到Bezier曲线上的一个点_venshine专栏-CSDN博客_德卡斯特里奥算法,基本上网上说的都是这篇的内容,我也是基于这篇来理解的,不过我也是反复看之后才有所理解,这里理解算法的核心得要理解透这句话才行:

    因为,有一个式子,跟我提前贴的代码中的式子很像呀:

    理解透了这个公式,那对于整个算法的核心就已经掌握了,这篇博主我看完之后其实还是有点懵懵的,最后理解到位是通过它:https://wenku.baidu.com/view/7ae91e260722192e4436f605.html

    其实两篇思想一样,只是这篇语言组织上详细通俗一点,咱们就根据两位大佬的博客,带着自己的理解来挼一挼:

    其中提到了“向量”这个词, 不知各位都对它还记得么,对我来说印象比较深刻,因为之前学了“线性代数”:

    如完全没印象的,可以移步到这线性代数学习之一切从向量开始 - cexo - 博客园瞅一瞅,图中所示的应该还是比较简单的,道出了这个算法的核心思想就是来找到C这个点的位置:

    其中为啥是“使得C分向量AB为u:1-u(即∣AC∣:∣AB∣= u)”,其实是将整个AB看成是1(why?),然后u是∣AC∣:∣AB∣,其中还知道“∣AC∣”是啥意思不?小学数学还是初中数学的知识了,表示AC两点的距离,复习下:

    那:

    那是不是:

    所以很显然C就把向量AB分成了u:1-u了。接下来则需要来解释上面标红的一句话了:“整个AB看成是1”,这里回忆一下最开始对于一阶贝塞尔曲线的执行过程:

    看到其中的t了么?最大就是1,因为曲线的绘制就是根据算出来的绘制点连线而成,而多少个绘制点则你可以自己来根据这个1进行拆分,可能这边说得有点绕,这里先把之后咱们实现时需要用到的一个代码先提前亮出来吧,这样就比较好理解了:

    当然现在贴代码有点超前,不过细节先不用关注,这里只是为了理解这个“1”,接下来的核心就是理解如何算C这个绘制点了,也就是博主的这句话:

    理解一下,“A到B的向量是B - A”,这个应该容易理解吧,就是指AB之间的距离嘛,然后C点占整个1的百分比是u,那么C点的位置很明显就是u * (B -A)嘛,这样就把C给算出来了呀,但是“考虑到A点的位置”,由于A点的位置不一定是原点,比如发生偏移之类的,那么整个C点的位置还得基于A的位置来算,所以整个式子就变成了“A + u(B - A)”,再根据结合率之类的,最终就可以变化成这个式子了:“(1 - u)*A + u*B”,其中是不是可以发现,只要我将u这个比例值知道了,整个C点的绘制位置就知道了?

    2、理解递归的逻辑:

    对于一个N阶贝塞尔曲线而言,你最终要绘制的只是最里面1阶贝塞尔曲线,所以光知道了,比如这样的一个五阶贝塞尔曲线的演变过程:

    也就是在计算过程中会涉及到N多个点对吧,但是绘制而言其实只需要它就可以了:

    很明显这里需要一个递归的过程最终再算出指定t下的贝塞尔曲线所在的那个绘制点对吧, 那递归的思路是啥呢?下面基于图中的这个场景来简单挼一下:

    其中的u为0.4,也就是该点是整个贝塞尔曲线40%的位置,说实话,这个递归过程不是那么好描述,其实就是降级的过程,最终降到一阶,其绘制点就给算出来了,这块具体的过程,我打算先把代码实现贴出来之后,再结合程序来进行理解,这样可能更加容易理解一点,所以这里的递归过程先忽略。

    3、实现四阶贝塞尔曲线:

    接下来直接来实现多阶贝塞尔曲线了,代码其实还是比较亲切的,如下:

    a、先将整个绘制分成1000等份,然后一等份一等份的算出绘制点:

    而具体算法,目前还未实现:

    b、完成绘制点的计算:

    /**
         * deCasteljau算法
         * p(i,j) =  (1-t) * p(i-1,j)  +  u * p(i-1,j-1);
         *
         * @param i 阶数   4
         * @param j 控制点 3
         * @param t 时间
         * @return
         */
        private float deCasteljauX(int i, int j, float t) {
            if (i == 1) {
                return (1 - t) * controlPoints.get(j).x + t * controlPoints.get(j + 1).x;
            }
            return (1 - t) * deCasteljauX(i - 1, j, t) + t * deCasteljauX(i - 1, j + 1, t);
        }
    
        /**
         * deCasteljau算法
         *
         * @param i 阶数
         * @param j 点
         * @param t 时间
         * @return
         */
        private float deCasteljauY(int i, int j, float t) {
            if (i == 1) {
                return (1 - t) * controlPoints.get(j).y + t * controlPoints.get(j + 1).y;
            }
            return (1 - t) * deCasteljauY(i - 1, j, t) + t * deCasteljauY(i - 1, j + 1, t);
        }

    整体的思路就是如果当前是1阶了,则直接根据德卡斯特里奥算法来算出绘制点,如果大于1阶的,则递归降级处理,具体的细节这里先不解释,因为下面会根据运行结果再来分析整个程序的执行过程的,这样你就明白了其递归的一个逻辑了。

    4、运行:

    接下来运行看一下,目前看的是4阶的效果,由于点是随机产生的,多运行几次,看曲线画得完不完美:

    嗯,挺完美的~~ 

    5、实现N阶贝塞尔曲线:

    为了验证这种方式的通用性,用两个极端的阶数来测试一下,一个是2阶,一个是7阶,先来看一个2阶的吧,咱们把程序写一个数字既可,其它完全不需要动:

    运行:

    接下来再看一下7阶的,同样改个数字既可:

    运行:

    完美,可见通过这种算法来实现的贝塞尔曲线可以满足所有阶次。 

    6、分析递归逻辑:

    好!!最后这里还遗留一个问题,那就是整个递归的思路是咋样的呢?对应的代码是:

    这里以三阶贝塞尔曲线绘制为例,来debug一下咱们的程序,为了方便分析,这里将随机的点改为定死的点,如下:

    先看一下运行的样子:

    注意,起始点和结束点的位置,因为关系到待会的逻辑分析涉及到的控制点的控制:

    而为了方便分析流程,这里将t定死一个,只分析一个绘制点既可,如下:

    目前长这样了:

    而为了更加精简,只分析一下坐标点的x的值计算过程既可,因为y值的计算过程是一模一样的,也就是它:

    另外,为了让分析代码变得清晰,这里将deCasteljauX调整一下:

    是不是这样跟咱们理论所分析的公式就一模一样了:

    这样分析递归也好分析一些,不然一行代码有两个递归看着有点晕,一切就绪,接下来进入代码分析阶段。

    开始分析:

    1、i=3,j=0:

    其中i代表是阶数,j代表的是控制点,也就是首先是来计算三阶的这

    由于阶数不是1,所以此时会进入递归环节。

    2、递归计算A点:float A = deCasteljauX(i - 1, j, t);

    在分析前,要明白目前分析的点是哪个,这里利用开源的BezierMaker来手动制造跟咱们分析的三阶贝塞尔曲线,因为它有降阶的辅助线供参考,所以对于想把贝塞尔曲线学好的强烈推荐这个工具,真的很方便,其实目前这句代码的目的就是为了算出它:

    【注意】:这里我制造效果时有点顺序问题,应该p0在p3的位置的,由于在写逻辑时已经基于这样的图进行了,这里就说明一下,p3是第一个点,p0是最后一个点【正常p0是第一个点,p3是最后一个点嘛,犯了个细节错误,将错就错了,不过不影响整体的逻辑理解】,这个注意一下!!!

    而这个A点的算出,很明显是需要根据降阶操作之后的这俩A,B点来算出,如下:

    所以,为了降阶,这里将阶数减一再次递归了:

    然后此时进入递归环节:

    由于阶数目前还是不等于1,又会执行到这:

    算二阶的A:

    而此时由于阶数已经降为2了,再递归降一级,就变为1阶了,此时结果就直接可以算出返回了:

    此时的A为619.23193,也就是这个点坐标的x值:

    算二阶的B:

    此时则开始算降阶的B点了:

    同样由于阶数已经还是2,再递归降一级,就变为1阶了,此时结果就直接可以算出返回了:

    此时的B为361.1466,也就是这个点坐标的x值:

    结果得出:

    此时再根据德卡斯特里奥算法,此时这个二阶上的点结果x值就出来了:

    也就是这个点算出来为482.70563:

    这里好好理会一下整个A值的计算过程,很明显的一个降级,也就是不管多少阶,最终都会递归降到1阶,然后再算出其中的A,B点的值,再算出最终的曲线绘制点,当然这个递归不是很好理解的,需要自己边画边挼一下才行。

    3、计算B点:float B = deCasteljauX(i - 1, j + 1, t);

    理清了A点的计算递归逻辑,这个B点的计算逻辑是一模一样的,同样在分析前,需要明确目标,这句代码的意思是算出它:

    而这个B点的算出,很明显是需要根据降阶操作之后的这俩A,B点来算出,如下:

    所以,为了降阶,这里将阶数减一再次递归了:

    然后注意,此时的j控制点+1了:

    这是因为此时B点的算出得根据第二个控制点来:

    是不是这两个点得基于p2起步来算出?所以这里的控制点数+1了,这个细节需要好好体会。

    然后此时进入递归环节:

    由于阶数目前还是不等于1,又会执行到这:

    算二阶的A:

    而此时由于阶数已经降为2了,再递归降一级,就变为1阶了,此时结果就直接可以算出返回了:

    此时的A为361.1466,也就是这个点坐标的x值:

    算二阶的B:

    此时则开始算降阶的B点了:

    同样由于阶数已经还是2,再递归降一级,就变为1阶了,此时结果就直接可以算出返回了:

    此时的B为213.16849,也就是这个点坐标的x值:

    结果得出:

    此时再根据德卡斯特里奥算法,此时这个二阶上的点结果x值就出来了:

    也就是这个点算出来为282.86667:

    4、根据德卡斯特里奥算法来算出结果:

    目前A,B两点已经算出来了,你说要绘制的这个点怎么得出应该就很简单了吧?

    这样,绘制点就成功算出:

    总结递归逻辑:

    经过这么完整的一个debug分析,是不是比直接分析代码要容易理解一些?对于递归的程序,如果当你光看代码不好理解的话,建议用debug的方式完整的梳理一遍,这样你就会比较容易理解,不过!!!整体还是比较晕的,这里最后再整理一下,其实递归的目的就是降级,降到1阶,递归的目的就是为了算出1阶的开始点和结束点:

    有了这俩点,最终绘制点就可以根据德卡斯特里奥算法来算出了。

     7、理解等份的含义:

    最后,咱们将debug时的一些代码给还原,最后再来看个东东,就是关于它的作用:

    之前不是说这个数值越大其绘制出来的曲线就越细腻么,为了体现,咱们改为很小,反着看一下,是不是越小,越不细腻,这里先把1000的图贴出来:

    然后咱们将其改为10,再对比看一下:

    是不是对比非常明显,等份小了,很明显点与点之间的距离大了,然后连线当然就不圆润了啦,通过这个对比应该就明白这个等份的意义了吧?

    总结:

    至此,我们已经学会了N阶贝塞尔曲线的画法了,但是!!!在之后咱们实现的QQ汽泡的效果时只会使用到Android Path API来绘制二阶贝塞尔曲线的,那这么复杂的算法有何意义呢?可以让你对贝塞尔曲线的概念理解得更加深刻呀,如果你只学Android API和二三阶贝塞尔曲线的用法,人家都把实现细节给你封装好了,能知道贝塞尔曲线的精髓么?这篇耗了我业余大概一周多时间梳理吧,收获反正是挺大的,有种茅塞顿开的感觉,如果你有心,建议自己写一篇博客从头至尾的按自己的思路来梳理分享出来,哪怕是网上参考的【但是一定得要带着自己的理解去解读,而不是直接copy】,这样你就能体会到虽说时间成本比较大,但是你的收获也很大,这也是为啥我一直坚持的原因,这样可以让自己摒弃浮躁,脚踏实地的一步步朝前走。

    本来计划还要实现一个qq汽泡的效果滴,不过在这个算法上花得篇幅较长,放下次吧。

    关注个人公众号,获得实时推送

     

    展开全文
  • 德卡斯特里奥算法的基础就是在向量AB上选择一个点C,使得C分向量AB为u:1-u(也就是∣AC∣:∣AB∣= u)。给定点A、B的坐标以及u(u∈[0,1])的值,点C的坐标便为:C = A + (B - A) * u = (1 - u)...

    贝塞尔曲线很多客户端已经自行集成,安卓ios或是web,今天基于算法动手实现一次,今天只放源码,暂时不做说明了(还要加班,--~),源码在下面,直接看也能看懂

    德卡斯特里奥算法的基础就是在向量AB上选择一个点C,使得C分向量ABu:1-u(也就是∣AC:AB= u)。给定点AB的坐标以及uu[0,1])的值,点C的坐标便为:C = A + (B - A) * u = (1 - u) * A + B * u

     

    我本来是做安卓的,不过安卓调试太慢了,我就用html实现了下 复制代码直接到txt改后缀html就可以看到效果了,其他语言和逻辑可以通用

    <!DOCTYPE HTML>
    <html>
    <body>
    
    <canvas id="BddCanvas" width="1000" height="500" style="border:1px solid #c3c3c3;">
    Your browser does not support the canvas element.
    </canvas>
    贝塞尔曲线N阶算法演示
    <script type="text/javascript">
    
    
    <!-- 拿到画布 -->
    var c=document.getElementById("BddCanvas")
    <!-- 拿到绘制环境 -->
    var canvasRC2D=c.getContext("2d")
    
    <!-- 测试4个控制点 -->
    var points_control=new Array(
    {x:10,y:10},
    {x:150,y:400},
    {x:300,y:40},
    {x:800,y:300})
    
    
    <!-- 先展示折线效果 -->
    canvasRC2D.moveTo(points_control[0].x,points_control[0].y)
    canvasRC2D.lineTo(points_control[1].x,points_control[1].y)
    canvasRC2D.lineTo(points_control[2].x,points_control[2].y)
    canvasRC2D.lineTo(points_control[3].x,points_control[3].y)
    
    
    <!-- 系统自带实现三阶贝塞尔的效果 --> 
    canvasRC2D.moveTo(points_control[0].x,points_control[0].y)
    canvasRC2D.bezierCurveTo(
    points_control[1].x,points_control[1].y,
    points_control[2].x,points_control[2].y,
    points_control[3].x,points_control[3].y
    )
    canvasRC2D.stroke() 
    
    
    //自己按原理算法实现
    <!-- //AB两点间符合要求的c 取向量 算法基础∣AC∣:∣AB∣= u (u∈[0,1]) C = A + (B - A) * u = (1 - u) * A + B * u -->
    //重新开始一条路径 采用红色和往下一点的起点+40作为区分
    canvasRC2D.beginPath()
    canvasRC2D.strokeStyle="red"
    canvasRC2D.lineWidth=3
    
    
    points_control=new Array(
    {x:10,y:10+40},
    {x:150,y:400+40},
    {x:300,y:40+40},
    {x:800,y:300+40})
    
    var x_start = points_control[0].x
    var y_start = points_control[0].y
    
    canvasRC2D.moveTo(x_start,y_start)
    
     //动态比例 越小曲线越细腻u = 0.01
    
    var time = 0
    for (var u=0;u<=1;u+=0.01){
    	for (var i=1;i<points_control.length;++i){
    
    		for (var j=0;j<points_control.length-i;j++){
    			console.log("time:"+time++);
    			if(i == 1){
    			
    				<!-- //根据上面公式 -->
    				points_control[j].x = parseInt((1 - u) * points_control[j].x + points_control[j + 1].x * u)
     				points_control[j].y = parseInt((1 - u) * points_control[j].y + points_control[j + 1].y * u)
    		
    			    continue
    				
    			}
    			<!-- //i != 1时,通过上一次迭代的结果计算 -->
    			points_control[j].x = points_control[j].x * (1 - u) + points_control[j + 1].x * u
    			points_control[j].y = points_control[j].y * (1 - u) + points_control[j + 1].y * u
    				
    		
    }
    	console.log("计算结果:x"+x_start);
    	//绘制线条
    	//canvasRC2D.moveTo(x_start,y_start)
    	canvasRC2D.lineTo(points_control[0].x,points_control[0].y)
    	//生成一个新点
    	x_start = points_control[0].x
     
    	y_start = points_control[0].y
    	
    	canvasRC2D.stroke()
    	
    }
    }
    
    <!-- //用延时展现绘制过程和外层循坏 多阶展现-->
    points_control=new Array(
    {x:10,y:10+80},
    {x:150,y:400+80},
    {x:300,y:40+80},
    {x:800,y:300+80},	
    {x:20,y:331},	
    {x:80,y:80},	
    {x:500,y:150},	
    {x:31,y:66},	
    {x:400,y:1},	
    {x:31,y:30},	
    {x:800,y:2},	
    {x:400,y:500},	
    {x:1000,y:1})
    
    x_start = points_control[0].x
    y_start = points_control[0].y
    
    canvasRC2D.beginPath()
    canvasRC2D.strokeStyle="green"
    canvasRC2D.lineWidth=3
    
    
    
    
    canvasRC2D.moveTo(x_start,y_start)
    
    	<!-- for (var i=0;i<points_control.length;i++){ -->
    		<!-- canvasRC2D.lineTo(points_control[i].x,points_control[i].y) -->
    	<!-- } -->
    	<!-- canvasRC2D.moveTo(x_start,y_start) -->
    
    u=0
    
    var interval=self.setInterval("clock()",30)
    function clock() { 
    
    	for (var i=1;i<points_control.length;++i){
    
    		for (var j=0;j<points_control.length-i;j++){
    		
    			if(i == 1){
    			
    				<!-- //根据上面公式 -->
    				points_control[j].x = parseInt((1 - u) * points_control[j].x + points_control[j + 1].x * u)
     				points_control[j].y = parseInt((1 - u) * points_control[j].y + points_control[j + 1].y * u)
    		
    			    continue
    				
    			}
    			<!-- //i != 1时,通过上一次迭代的结果计算 -->
    			points_control[j].x = points_control[j].x * (1 - u) + points_control[j + 1].x * u
    			points_control[j].y = points_control[j].y * (1 - u) + points_control[j + 1].y * u
    
    	}
    
    	//绘制线条
    	//canvasRC2D.moveTo(x_start,y_start)
    	canvasRC2D.lineTo(points_control[0].x,points_control[0].y)
    	//生成一个新点
    	x_start = points_control[0].x
     
    	y_start = points_control[0].y
    	
    	canvasRC2D.stroke()
    	
    	u+=0.001
    	
    	
    	if(u>=1){
    	clearInterval(interval)
    }
    }
    }
    
    
    </script>
    </body>
    </html>

    //核心部分讲解

    展开全文
  • 德卡斯特里奥算法——找到Bezier曲线上的一个点

    千次阅读 多人点赞 2016-06-24 10:52:26
    德卡斯特里奥算法的基本思想是在向量AB上选择一个点C,使得C分向量AB为u:1-u(即∣AC∣:∣AB∣= u)。我们找到一种方法来确定点C。 向量A到B记做B-A,因为u∈[0,1],点C在u(B-A)上。以A点坐标作为起始点,点C...

    http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html

    随着Bezier曲线的构造,接下来最重要的任务就是通过给定的u值查找Bezier曲线上的点C(u)。一个简单的方法就是将u值插入到每一个基函数中,计算每个基函数的乘积及其相应的控制点,并最终将它们加在一起。尽管它有很好的效果,但这并不是数值稳定的(即在求伯恩斯坦多项式的时候可能会引入数值误差)。

    在下文中,我们将只写下控制点的编号。即控制点00当作P0,01当作P1,…,0i当作Pi,…,0n当作PN。其中0表示初始值或第0次迭代,接下来是1、2、3……

    德卡斯特里奥算法的基本思想是在向量AB上选择一个点C,使得C分向量AB为u:1-u(即∣AC∣:∣AB∣= u)。我们找到一种方法来确定点C。

    向量A到B记做B-A,因为u∈[0,1],点C在u(B-A)上。以A点坐标作为起始点,点C坐标为A + u(B - A) = (1 - u)A + uB。因此给定一个u值,(1 - u)A + uB使C点分向量AB为u:1-u。

    德卡斯特里奥算法的思想如下:
    假设我们想要找到点C(u),u∈[0,1],从第一条折线开始,00-01-02-03…-0n。利用上面的公式,我们可以在线段0i到0(i+1)上找到一点1i,使得该点分向量0i和0(i+1)位u:1-u。以此类推,我们会找到N个点,10, 11, 12, …., 1(n-1)。它们连在一起,构成了(n-1)长度的新的折线。

    上图中,u等于0.4。点10在00和01线段中,点11在01和02线段中,……,点14在04和05线段中。所有这些新加入的点都用蓝色标记。

    新点的编号是1i,应用这条新折线我们将会获得由n-1个点组成的第二条折线,20, 21, …, 2(n-2),长度n-2。通过这条折线,我们又可以获得由n-2个点组成的第三条折线,30, 31, …, 3(n-3),长度n-3。重复N次这个过程,就会最终产生一个唯一的点N0。德卡斯特里奥证明了这个点就是点C(u)在曲线上的点。

    我们继续上面的计算,从图中可以看到,点20在10和11线段中分线段为u:1-u。同样地,点21在11和12线段中,点22在12和13线段中,点23在13和14线段中。通过20、21、22、23四个点连接组成了第三条折线。第三条折线包含4个点和3个线段。持续这么做,我们将会得到由30、31、32三个点组成的第四条折线。通过第四条折线,我们将会得到由40、41两个点组成的第五条折线。再做一次,我们获得了点50。这个点就是C(0.4)在曲线上的点。

    以上就是德卡斯特里奥算法的几何说明,最优美的曲线设计之一。


    实际计算

    通过上面对德卡斯特里奥算法的几何说明,我们提出了一个计算方法,如下图所示。

    首先,所有给定的控制点被排成一列,在图中最左边所示。每一对相邻的控制点通过两个箭头指向新的控制点。例如,两个相邻控制点ij和i(j+1)生成新的控制点(i+1)j。指向东南方向的箭头表示在它尾部的点乘以(1-u),指向东北方向的箭头表示在它尾部的点乘以u。ij和i(j+1)即为新点的总和。

    因此,从最初的第0列,我们可以计算出第1列。通过第1列,我们又能获得第2列。以此计算下去,在n此迭代后,最终我们会获得一个单独的点n0,这个点就是曲线上的点。下面的算法总结了我们所讨论的问题。由n+1个点构成的数组P和在0到1范围内的一个u值,返回Bezier曲线上的点C(u)。

    Input: array P[0:n] of n+1 points and real number u in [0,1] 
    Output: point on curve, C(u) 
    Working: point array Q[0:n] 
    
    for i := 0 to n do 
    Q[i] := P[i]; // save input 
    for k := 1 to n do 
    for i := 0 to n - k do 
    Q[i] := (1 - u)Q[i] + u Q[i + 1];
    return Q[0];

    一个递推关系

    上面的计算可以通过递推表示。开始时,设P0,j作为Pj在0到n次循环后的值,即P0,j是第0列第j次。第i列第j次计算公式如下:

    更确切地说,Pi,j是(1-u)Pi-1,j和uPi-1,j+1的和。最终结果(即曲线上的点)是Pn,0。有了这个想法,你可能会很快想出以下递归程序:

    function deCasteljau(i,j) 
    begin 
    if i = 0 then 
    return P0,j 
    else 
    return (1-u)* deCasteljau(i-1,j) + u* deCasteljau(i-1,j+1)
    Pn-1,0

    这段程序看起来很简短,但是它非常低效。原因就在于,我们调用deCasteljau(n,0)计算Pn,0,这时else部分又调用两次,调用deCasteljau(n-1,0)计算Pn-1,0,调用deCasteljau(n-1,1)计算Pn-1,1。

    考虑调用Decasteljau(n-1,0)。它分成两次调用,Decasteljau(n-2,0)计算Pn-2,0同时Decasteljau(n-2,1)计算Pn-2,1。调用Decasteljau(n-1,1)分成两次调用,Decasteljau(n-2,1)计算Pn-2,1同时Decasteljau(n-2,2)计算Pn-2,2。因此,Decasteljau(n-2,1)被调用两次。如果我们继续扩大这些函数的调用,我们会发现,为了计算Pi,j的值,几乎所有的函数都被重复调用过,不仅仅被调用一次,可能是很多次。J是重复的,而不是一次,但许多次。这有多糟糕?事实上,上述的计算方案和以下方式计算第n个Fibonacci数相同:

    function Fibonacci(n)
    begin
    if n = 0 or n = 1 then 
    return 1 
    else
    return Fibonacci (n-1) + Fibonacci (n-2)
    end

    这段程序消耗了一个指数量级的函数调用来计算Fibonacci数。因此,德卡斯特里奥算法的递归版本不适合直接实现,虽然它看起来简单和优雅!


    一个有趣的性质

    德卡斯特里奥算法的三角形计算方案给我们提供了一个有趣的性质。观察下面计算,通过8个控制点00, 01, …, 07定义了7阶Bezier曲线。我们把同一列中一组连续的点作为Bezier曲线的控制点。那么,给定一个u值,u∈[0,1],我们如何在Bezier曲线上计算出这个对应的点?如果德卡斯特里奥算法使用了这些控制点,那么曲线上的点就是由选定的点组成的等边三角形中与这些控制点相对的顶点。

    例如,如果选择02,03,04和05四个点,由这四个控制点确定的曲线上,其对应的u点就是32。观察上图蓝色的三角形。如果选中的点是11,12,13,曲线上的点就是31。观察上图黄色的三角形。如果选中的点是30,31,32,33,34,曲线上的点就是70。

    基于同样的原因,70也是Bezier曲线控制点60和61定义的点。它也是由52,51和50定义的曲线上的点,并在40,43,42和41定义的曲线上。总的来说,如果我们选择一个点,画一个等边三角形如上图所示,由选中的这些控制点组成的等边三角形的定点就能被计算出来。

    展开全文
  • 德卡斯特里奥算法可以计算贝塞尔曲线上的点C(u),u∈[0,1]。因此,通过给定一组u的值,便可以计算出贝塞尔曲线上的坐标序列,从而绘制出贝塞尔曲线。 德卡斯特里奥算法的基础就是在向量AB上选择一个点C,使得C分...
  • 计算机图形学实验de-Casteljau算法知识讲解.docx计算机图形学实验de-Casteljau算法知识讲解.docx计算机图形学实验de-Casteljau算法知识讲解.docx计算机图形学实验de-Casteljau算法知识讲解.docx计算机图形学实验de-...
  • 这篇文章比较好理解些~ ...写递归算法的话,核心应该是:  p(i,j) = (1-u) * p(i-1,j) + u * p(i-1,j-1);   恩,觉得今天理解的差不多了,代码回头写写试试~~~
  • 贝齐埃曲线德卡斯特里奥(de Casteljau)算法及程序 1) 描述de Casteljau算法最基本的概念就是在线段AB中找到C点,使得C点将AB线段划分成u:(1-u)比例(|AC|:|AB|=u),怎么找这个C点呢? A 到 B 的向量是 B – A ...
  • 贝塞尔曲线德卡斯特里奥(de Casteljau)算法及程序 设P0、P02、P2是一条抛物线上顺序三个不同的点。过P0和P2点的两切线交于P1点,在P02点的切线交P0P1和P2P1于P01和P11,则如下比例成立:   这是所谓抛物线的三...
  • 以伯恩斯坦形式评估多项式的数值稳定方法是de Casteljau算法 但直到 1959 年,当时就职于雪铁龙的法国数学家 Paul de Casteljau 才开始对它进行图形化应用的尝试,并提出了一种数值稳定的 de Casteljau 算法。然而...
  • Android代码-BezierMaker

    2019-08-07 09:57:48
    想深入了解德卡斯特里奥算法的同学可以参考我翻译的一篇文章《德卡斯特里奥算法——找到Bezier曲线上的一个点》。 bezier.apk Features 支持增加和删除控制点 支持1阶到7阶贝塞尔曲线,限于屏幕大小,理论上可以...
  • 想深入了解德卡斯特里奥算法的同学可以参考我的翻译文章 。 产品特点 支持增加和删除控制点 支持1阶到7阶贝塞尔曲线,范围屏幕大小,理论上可以支持N阶贝塞尔曲线 支持自由移动控制点 支持显示贝塞尔曲线形成过程的...
  • Android 贝塞尔曲线原理及其绘制实现

    千次阅读 2019-11-29 17:44:32
    Android动画,特别是涉及运动轨迹的,很多时候都会使用贝塞尔曲线...贝塞尔曲线最初由保尔·德·卡斯特里奥于1959年运用德卡斯特里奥算法开发,以稳定数值的方法求出贝塞尔曲线。 下文我们将简要介绍德卡斯特里奥算...
  • 计算机图形学实验de-Casteljau算法精品文档精品文档收集于网络,如有侵权请联系管理员删除收集于网络,如有侵权请联系管理员删除精品文档收集于网络,如有侵权请联系管理员删除实验7-2一、实验题目在屏幕上使用鼠标...
  • De Casteljau算法

    2016-12-01 15:42:11
    在屏幕上使用鼠标绘制任意控制点的控制多边形,基于de casteljau算法绘制所示的BEZIER曲线
  • 接着上一次算法与数据结构基础<三>----数据结构基础之栈和队列加强之用栈实现队列 - cexo - 博客园的数据结构继续往下学习,这次会进入一个非常重要的数据结构的学习----链表,这个是未来学习复杂算法的一个...
  • 最初由保罗·德卡斯特里奥(Paul de Casteljau)于1959年运用德卡斯特里奥算法开发(de Casteljau Algorithm),在1962,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表。目前广泛应用于图形绘制领域来...
  • Android 绘制N阶Bezier曲线

    万次阅读 2016-06-25 16:04:39
    在这里我就不解释这段代码了,不懂的同学可以参考上一段解释,看我翻译的德卡斯特里奥算法。 private ArrayList<ArrayList<ArrayList<PointF>>> buildTangentPoints () { ArrayList<PointF> points; // 1条...
  • 原 原地算法 启 启发式搜索 埃 埃拉托斯特尼筛法 大 大步小步算法 大英博物館算法 奎 奎因-麦克拉斯基算法 密 密码强度 对 对立度算法 左 左偏树 布 布斯乘法算法 并 并行排序 德 德卡斯特里奥算法 德布尔算法 快 ...
  • 使用了德卡斯特里奥算法 来计算曲线轨迹点,参考文章 https://blog.csdn.net/venshine/article/details/51750906 BezierData 贝塞尔曲线数据类,用于存储控制点,计算曲线轨迹点 public class BezierData ...
  • ---基本概念、德卡斯特里奥算法 - cexo - 博客园对于贝塞尔曲线的绘制方法进行了一个基础学习,接下来则利用贝塞尔曲线来实际应用一把,其效果之前也展示过,如下: 由于之前QQ气泡效果剖析 - cexo - 博客园还...
  • 通过 de Casteljau 算法绘制贝塞尔曲线,并计算它的切线,实现 1-7 阶贝塞尔曲线的形成动画。
  • Bezier曲线原理

    万次阅读 2012-09-13 15:10:58
    一、原理: ... de Casteljau 于1959年运用de Casteljau 算法开发,以稳定数值的方法求出贝塞尔曲线。 线性贝塞尔曲线 给定点 P0、P1,线性贝塞尔曲线只是一条两点之间的直线。这条线由下式给出

空空如也

空空如也

1 2 3 4 5 6
收藏数 112
精华内容 44
关键字:

德卡斯特里奥算法