java实现曲线运动_贝塞尔曲线 --匀速贝塞尔曲线运动的实现
二次贝塞尔曲线通常以如下方式构建,给定二维平面上的固定点P0,P1,P2,用B(t)表示该条曲线
用一个动画来演示,可以更加清楚的表明这条曲线的构建过程
如果t变量本身线形变化的话,这条贝塞尔曲线本身的生成过程是并不是匀速的,通常都是两头快中间慢。
如何想要得到匀速的贝塞尔曲线运动呢?比如我们在某款游戏中设计了一条贝塞尔曲线的路径,如何实现玩家匀速在这条路径上运动呢?
首先需要求得B(t)相对于t的速度公式s(t)
为了简化公式,我们定义如下变量
计算出的s(t)可以表达为
其中A,B,C是根据P0,P1,P2计算出的常数
根据这个公式,求得贝塞尔曲线的长度公式L(t)
设t`就是能够使L实现匀速运动的自变量,那么显然L(t`)=L(1.0)*t,即
由于L(t)函数非常复杂,直接求逆函数的表达式几乎不可能,还好我们可以知道它的导数为s(t),在实际使用中,可以使用牛顿切线法求出近似解。其迭代算法可以表达为
我写了一个测试程序用于验证该算法,运算结果如下,可以看到,这条曲线已经是以匀速方式生成的了
完整的示例源代码附载下面:
#include #include #include
//三个控制点
POINT P0={50,50},P1={500,600},P2={800,200};
int ax = P0.x-2*P1.x+P2.x;
int ay = P0.y-2*P1.y+P2.y;
int bx = 2*P1.x-2*P0.x;
int by = 2*P1.y-2*P0.y;
double A = 4*(ax*ax+ay*ay);
double B = 4*(ax*bx+ay*by);
double C = bx*bx+by*by;
//曲线总长度
double total_length = 0.0;
//曲线分割的份数
const int STEP = 70;
//用于保存绘制点数据的数组
POINT pixels[STEP];
//————————————————————————————-
//速度函数
/*
s(t_) = Sqrt[A*t*t+B*t+C]
*/
double s(double t)
{
return sqrt(A*t*t+B*t+C);
}
//————————————————————————————-
//长度函数
/*
L(t) = Integrate[s[t], t]
L(t_) = ((2*Sqrt[A]*(2*A*t*Sqrt[C + t*(B + A*t)] + B*(-Sqrt[C] + Sqrt[C + t*(B + A*t)])) +
(B^2 – 4*A*C) (Log[B + 2*Sqrt[A]*Sqrt[C]] – Log[B + 2*A*t + 2 Sqrt[A]*Sqrt[C + t*(B + A*t)]]))
/(8* A^(3/2)));
*/
double L(double t)
{
double temp1 = sqrt(C+t*(B+A*t));
double temp2 = (2*A*t*temp1+B*(temp1-sqrt(C)));
double temp3 = log(B+2*sqrt(A)*sqrt(C));
double temp4 = log(B+2*A*t+2*sqrt(A)*temp1);
double temp5 = 2*sqrt(A)*temp2;
double temp6 = (B*B-4*A*C)*(temp3-temp4);
return (temp5+temp6)/(8*pow(A,1.5));
}
//————————————————————————————-
//长度函数反函数,使用牛顿切线法求解
/*
X(n+1) = Xn – F(Xn)/F’(Xn)
*/
double InvertL(double t, double l)
{
double t1=t, t2;
do
{
t2 = t1 – (L(t1)-l)/s(t1);
if(abs(t1-t2)<0.000001) break;
t1=t2;
}while(true);
return t2;
}
//————————————————————————————-
LRESULT CALLBACK _WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_TIMER:
{
static nIndex = 0;
if(nIndex>=0 && nIndex<=STEP)
{
double t = (double)nIndex/STEP;
//如果按照线形增长,此时对应的曲线长度
double l = t*total_length;
//根据L函数的反函数,求得l对应的t值
t = InvertL(t, l);
//根据贝塞尔曲线函数,求得取得此时的x,y坐标
double x = (1-t)*(1-t)*P0.x +2*(1-t)*t*P1.x + t*t*P2.x;
double y = (1-t)*(1-t)*P0.y +2*(1-t)*t*P1.y + t*t*P2.y;
//取整
pixels[nIndex].x = (int)(x+0.5);
pixels[nIndex].y = (int)(y+0.5);
nIndex++;
InvalidateRect(hWnd, 0, 0);
}
else
{
KillTimer(hWnd, 101);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
::MoveToEx(hdc, P0.x, P0.y, 0);
LineTo(hdc, P1.x, P1.y);
LineTo(hdc, P2.x, P2.y);
for(int i=0; i{
const POINT &pt = pixels[i];
if(pt.x==0 && pt.y==0) break;
::MoveToEx(hdc, pt.x-2, pt.y, 0);
::LineTo(hdc, pt.x+2, pt.y);
::MoveToEx(hdc, pt.x, pt.y-2, 0);
::LineTo(hdc, pt.x, pt.y+2);
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//————————————————————————————-
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//注册窗口类
WNDCLAS*** wcex;
ZeroMemory(&wcex, sizeof(WNDCLAS***));
wcex.cbSize = sizeof(WNDCLAS***);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)_WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = “BezierClass”;
RegisterClas***(&wcex);
//创建窗口
HWND hWnd = CreateWindow(“BezierClass”, “BezierDemo”, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//计算总长度
total_length = L(1);
//清空绘制点数据
ZeroMemory(&pixels, sizeof(pixels));
//设定定时刷新计时器
SetTimer(hWnd, 101, 10, 0);
//消息循环
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
java实现曲线运动_贝塞尔曲线 --匀速贝塞尔曲线运动的实现相关推荐
- 多视角探析贝塞尔曲线匀速化技术、实现及其应用
概述 就在三年前,我于CSDN博客上发布了一篇题为<贝塞尔曲线运动n阶追踪方程的数学原理及其匀速化方法和应用>的博客文章,主要探讨的是贝塞尔曲线由一阶至n阶在数学层面的生成过程,以及匀速化 ...
- 光滑曲线_计算机图形学十:贝塞尔曲线与贝塞尔曲面
贝塞尔曲线与贝塞尔曲面 1 贝塞尔曲线(Bézier Curves) 在进入具体原理讲解之前,首先看一下一条实际的贝塞尔曲线长什么样子 其中 为 控制点,蓝色所表示曲线正是非常著名的贝塞尔曲线了,可以 ...
- 【Android UI】贝塞尔曲线 ② ( 二阶贝塞尔曲线公式 | 三阶贝塞尔曲线及公式 | 高阶贝塞尔曲线 )
文章目录 一.二阶贝塞尔曲线公式 二.三阶贝塞尔曲线 三.高阶贝塞尔曲线 贝塞尔曲线参考 : https://github.com/venshine/BezierMaker 一.二阶贝塞尔曲线公式 二 ...
- 【Android UI】贝塞尔曲线 ① ( 一阶贝塞尔曲线 | 二阶贝塞尔曲线 )
文章目录 一.一阶贝塞尔曲线 二.二阶贝塞尔曲线 贝塞尔曲线参考 : https://github.com/venshine/BezierMaker 一.一阶贝塞尔曲线 一阶贝塞尔曲线 本质 是一条直 ...
- 贝塞尔曲线和贝塞尔曲面_TimelineMax:处理贝塞尔(Bézier)补间
贝塞尔曲线和贝塞尔曲面 当您需要高级功能时,GSAP插件非常有用. 我将在本教程中解释的BezierPlugin可以帮助沿定义为点/值数组的弯曲贝塞尔曲线路径上的几乎任何一个或多个属性设置动画. 在跳 ...
- 贝塞尔曲线 java_贝塞尔曲线理论及实现——Java篇
贝塞尔曲线贝塞尔曲线(The Bézier Curves),是一种在计算机图形学中相当重要的参数曲线(2D,3D的称为曲面).贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézi ...
- Bézier曲线 和 Bézier曲面 ( 贝塞尔曲线 和 贝塞尔曲面 )
Bézier曲线 定义 给定空间n+1个点的位置矢量Pi(i=0,1,2-),则Bezier参数曲线上各点坐标的插值公式是:P(t)=∑i=0nPiBi,n(t),t∈[0,1]P(t)=\sum_{ ...
- android 贝塞尔曲线 人脸,贝塞尔曲线绘制人脸框(框内全透明,框外半透明)
参考CropImage 制作截取头像框https://github.com/cokeduo/CropImage https://www.jianshu.com/p/c883fbf52681 //贝塞尔 ...
- 贝塞尔曲线与贝塞尔曲面
1. 贝塞尔曲线(Bézier Curves) 在进入具体原理讲解之前,首先看一下一条实际的贝塞尔曲线长什么样子 其中为控制点,蓝色所表示曲线正是非常著名的贝塞尔曲线了,可以从图中观察到,曲线会与初始 ...
最新文章
- Linux C编程--进程间通信(IPC)4--管道详解
- 在Spark中自定义Kryo序列化输入输出API(转)
- word 文档操作类,可以读出word中书签 批量替换内容,直接调用
- FPGA病房呼叫系统实现
- 简单的python流回显服务器与客户端
- php 跳板机连接mysql,使用python如何通过跳板机连接MySQL数据库
- 机器学习笔记(十六)——EM算法概述
- Node.js安装及环境配置(windows)
- (转)Hibernate的优化方案
- windows linux—unix 跨平台通信集成控制系统
- 实现三栏布局的几种方法
- 完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三2-转
- 最常见到的runtime exception 异常
- cocos2d-x学习记录3——CCTouch触摸响应
- 问题:sql server 2005 中数据库关系图无法使用——基于SQL Server 2005
- 4. Firebug 调试 Js
- 疫情核酸检测,应考虑使用刷身份证的方式
- 判断用户端有无安装flash插件并返回对应播放器选项提示
- Python学习笔记——cmd提示pip不是内部或外部命令解决方法
- Oracle 同义词,赋权语句图解记录
热门文章
- 关于虚拟视点生成(Depth Based Image Rendering)问题
- java spring+ssm校园环保与维护平台
- uniapp Line授权登录
- 使用雷达测量心率和呼吸频率项目(1)-总体介绍
- 【Python】 面向对象:输出年龄最大的对象所对应的名字
- 段子男子和计算机说话视频教程,内涵段子怎么发视频 内涵段子发视频方法教程...
- 多轮对话-2020:DialoGPT【生成式多轮对话模型】
- linux go服务器吗,Linux之CentOS上部署安装goproxy服务端
- 谷歌Pixel3刷机指南——线刷
- Spring Cloud Config配置服务