采用Cardinal法构造插枝分段三次样条曲线 : 实战篇

原创 2006年05月30日 10:39:00

 

版权声明:

 

本文由timewolf完成,首发于CSDN,作者保留版权。
未经许可,不得使用于任何商业用途。
欢迎转载,但请保持文章及版权声明完整。
如需联络请发邮件:karla9(AT)eyou(dot)com

下面会给出一个简单的例子: 在窗口上用鼠标点8个点,然后就会将这8个点的坐标画出来~~~, 我共总用了3支画笔: 一支绿笔是将这些点用GDI+的画法画出来,一支蓝笔是将这些点画直线画出来,第三支红笔使用我的Cardinal方法画出来,从结果中我们可以看到,当t==0的时候,Cardinal画出来的曲线和GDI+的曲线完全重合

开发环境:VS.net 2003

使用方法:新建一个windows form项目, 将下面的代码拷贝至Form1.cs中覆盖之,然后run就行,然后就随便用鼠标点8个点吧

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;


namespace GDIplusApplication1
{
 #region the defination of MyArrayList
 class MyArrayList
 {
  private ArrayList data = new ArrayList();

  public MyArrayList()
  {
  }


  public Object this[int idx]
  {
   get
   {
    if (idx > -1 && idx < data.Count)
    {
     return (data[idx]);
    }
    else
    {
     throw new InvalidOperationException("[MyArr.set_Item] Index out of range");
    }
   }
   set
   {
    if (idx > -1 && idx < data.Count)
    {
     data[idx] = value;
    }
    else if (idx == data.Count)
    {
     data.Add(value);
    }
    else if (idx > data.Count)
    {
     for (int i = data.Count; i < idx; i++)
     {
      data.Add(null);
     }
     data.Add(value);
    }
    else
    {
     throw new InvalidOperationException("[MyArr.set_Item] Index out of range");
    }
   }
  }

  public int Count
  {
   get
   {
    return data.Count;
   }
  }

  public void Add(Object obj)
  {
   data.Add(obj);
  }

  public Array ToArray(Type type)
  {
   if (type == null)
   {
    throw new ArgumentNullException("type");
   }
   Array array1 = Array.CreateInstance(type, data.Count);
   array1 = data.ToArray(type);
   return array1;
  }
 }
 #endregion

 /// <summary>
 /// Summary description for Form1.
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
  public struct Point3D
  {
   public float x;
   public float y;
   public float z;
  }

  private MyArrayList mousePoints = new MyArrayList();
  Pen redPen = new Pen(Color.Red, 2);
  Pen bluePen = new Pen(Color.Blue, 2);
  Pen greenPen = new Pen(Color.Green, 2);
  Pen brownPen = new Pen(Color.Brown, 2);
  PointF lastPoint = new PointF(0, 0);
  PointF currentPoint = new PointF(0, 0);
  System.Drawing.Graphics g;

  /// <summary>
  /// Required designer variable.
  /// </summary>
  private System.ComponentModel.Container components = null;

  public Form1()
  {
   //
   // Required for Windows Form Designer support
   //
   InitializeComponent();
   g = this.CreateGraphics();

   //
   // TODO: Add any constructor code after InitializeComponent call
   //
  }


  /// <summary>
  /// Clean up any resources being used.
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }


  #region Windows Form Designer generated code
  /// <summary>
  /// Required method for Designer support - do not modify
  /// the contents of this method with the code editor.
  /// </summary>
  private void InitializeComponent()
  {
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
   this.ClientSize = new System.Drawing.Size(640, 526);
   this.Name = "Form1";
   this.Text = "Form1";
   this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
   this.Click += new System.EventHandler(this.Form1_Click);

  }
  #endregion

  /// <summary>
  /// The main entry PointF for the application.
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  #region Cardinal algorithm
  private PointF Cardinal(float u, float t, PointF A, PointF B, PointF C, PointF D)
  {
   float s = (1 - t) / 2;
   PointF resultPoint = new PointF();
   resultPoint.X = GetResult(A.X, B.X, C.X, D.X, s, u);
   resultPoint.Y = GetResult(A.Y, B.Y, C.Y, D.Y, s, u);
   return resultPoint;
  }

  private float GetResult(float a, float b, float c, float d, float s, float u)
  {
   float result = 0.0F;
   result = a*(2*s*u*u - s*u*u*u - s*u) + b*((2-s)*u*u*u + (s-3)*u*u + 1) +
         c*((s-2)*u*u*u + (3-2*s)*u*u + s*u) + d*(s*u*u*u - s*u*u);
   return result;
  }
  #endregion

  private void Form1_Click(object sender, System.EventArgs e)
  {
   Point currentPosition = Control.MousePosition;
   PointF currentMousePosition = (PointF)this.PointToClient(currentPosition);
   mousePoints.Add(currentMousePosition);
   currentPoint = currentMousePosition;

   if (mousePoints.Count == 8)
   {
    // the system curve, it's good
    GraphicsPath path = new GraphicsPath();
    path.AddCurve((PointF[])mousePoints.ToArray(typeof(PointF)));
    PointF[] newPoints = path.PathPoints;
    System.Drawing.Drawing2D.Matrix matrix = new Matrix();
    g.DrawLines(bluePen, (PointF[])mousePoints.ToArray(typeof(PointF)));
    g.DrawPath(greenPen, path);

    ArrayList newMousePoints = new ArrayList();
    PointF startPoint = (PointF)mousePoints[0];
    PointF starterPoint = new PointF(startPoint.X, startPoint.Y);
    PointF endPoint = (PointF)mousePoints[mousePoints.Count - 1];
    PointF enderPoint = new PointF(endPoint.X, endPoint.Y);
    newMousePoints.Add(starterPoint);

    for (int i = 0; i < mousePoints.Count; i++)
    {
     newMousePoints.Add(mousePoints[i]);
    }

    newMousePoints.Add(enderPoint);

    DateTime nowTime = System.DateTime.Now;
    TimeSpan startSpan = new TimeSpan(nowTime.Day, nowTime.Hour, nowTime.Minute, nowTime.Second, nowTime.Millisecond);

    for (int i = 0; i < 7; i++)
    {
     float uVaule = 0.000F;
     float step = 0.002F;
     ArrayList ctlPoints = new ArrayList();
     ctlPoints.Add(newMousePoints[i + 1]);
     while (uVaule < 1.0000F)
     {
      PointF newPoint = Cardinal(uVaule, 0.0F, (PointF)newMousePoints[i], (PointF)newMousePoints[i+1],
       (PointF)newMousePoints[i+2], (PointF)newMousePoints[i+3]);
      ctlPoints.Add(newPoint);
      uVaule += step;
     }
     ctlPoints.Add(newMousePoints[i + 2]);
     g.DrawLines(redPen, (PointF[])ctlPoints.ToArray(typeof(PointF)));
    }

    DateTime endTime = System.DateTime.Now;
    TimeSpan endSpan = new TimeSpan(endTime.Day, endTime.Hour, endTime.Minute, endTime.Second, endTime.Millisecond);
    TimeSpan elipSpan = endSpan.Subtract(startSpan);
    Console.WriteLine(elipSpan.ToString());
   }
  }

 }
}

[计算机动画] 路径曲线与运动物体控制(Cardinal样条曲线)

•路径曲线与运动物体控制 •掌握Cardinal样条曲线的表示和算法,了解控制参数对曲线形状的影响。 •对照Cardinal样条曲线的数学表示和程序代码的对应关系。 •在路径曲线上放置一小汽车,使其在...
  • ZJU_fish1996
  • ZJU_fish1996
  • 2016年10月05日 00:58
  • 3166

采用Cardinal法构造插枝分段三次样条曲线 : 实战篇

  版权声明:   本文由timewolf完成,首发于CSDN...
  • timewolf
  • timewolf
  • 2006年05月30日 10:39
  • 2393

网格模型obj文件及其纹理解析

最近在学习obj文件格式,上网查了些资料,很难找到比较全面的文章,尤其是对.mtl文件的说明甚少。今天把最近搜索的资料整合了一下。 常见到的*.obj文件有两种:第一种是...
  • qq_33854260
  • qq_33854260
  • 2017年04月28日 09:36
  • 843

采用Cardinal法构造插枝分段三次样条曲线 : 原理篇

       Cardinal样条是插值分段三次曲线,并且每条曲线段的终点位置均指定切线.不过Cardinal样条不用给出终点的切线值.在Cardinal样条中,一个控制点的斜率可以由两个相邻控制点的...
  • timewolf
  • timewolf
  • 2006年05月29日 17:11
  • 3941

采用Cardinal法构造插枝分段三次样条曲线 : 代码篇

说明:Spline类就是Cardinal样条曲线了,这个类里面记录了4个控制点:m_startControlPoint, m_startPoint, m_endPoint, m_endControlP...
  • timewolf
  • timewolf
  • 2006年05月30日 10:29
  • 2867

D3形状(二):曲线工厂

给定一系列的点,d3.line除了可以将这些点转换为折线路径外,还可以利用曲线工厂,将这些点转换为各类曲线,并能调节这些曲线的参数,改变曲线的形态。...
  • yiifaa
  • yiifaa
  • 2016年08月18日 15:14
  • 650

3D中的OBJ文件格式详解

常见到的*.obj文件有两种:第一种是基于COFF(Common Object File Format)格式的OBJ文件(也称目标文件),这种格式用于编译应用程序;第二种是Alias|Wavefron...
  • shenshen211
  • shenshen211
  • 2016年06月23日 09:58
  • 6547

样条曲线概述

1 背景 参考资料 [1]计算机图形学(第三版),电子工业出版社 [2]计算方法(第2版),电子工业出版社...
  • Q1302182594
  • Q1302182594
  • 2016年01月20日 22:43
  • 3444

三次样条曲线

阅读 Cocos2d-x 源码的时候,有几个有趣的关于路径运动的 Test Case 之前一直没有时间去研究:ActionCardinalSpline 和 ActionCatmullRom。由于对 B...
  • guggy
  • guggy
  • 2016年05月27日 10:47
  • 1307

3D中的OBJ文件格式详解

http://www.cnblogs.com/slysky/p/4081307.html常见到的*.obj文件有两种:第一种是基于COFF(Common Object File Format)格式的O...
  • u013467442
  • u013467442
  • 2015年11月29日 17:28
  • 5416
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:采用Cardinal法构造插枝分段三次样条曲线 : 实战篇
举报原因:
原因补充:

(最多只允许输入30个字)