zoukankan      html  css  js  c++  java
  • 在简单地形上小车运动轨迹的数学表达(二)

    在简单地形上小车运动轨迹的数学表达(二)

    图形学课上的小小总结


    前言

    在上一篇文章中已经把小车四个轮子的位置都计算出来了。在小车的运动过程中,光是小车运动是不实际的,现实生活中车体会随着地形有起有伏,而且运动是在紧附在轮子上的。因此,可以根据轮子的坐标进而得到小车车体[*]的运动轨迹。

    [*] 车体是指不包括车轮部分,后文也是如此。

    前提

    1. 车体是个平行六面体(实际为长方体)。

    2. 不考虑地形比触碰到车体的情况。

    根据上一篇文章的内容,可以得到这样的结果(图-1)


    问题一:如何做出车体的运动轨迹?

    该车体所拥有的特点是与前轮后轮所在轴垂直(图-2)(图还凑合。。。啦):

    其实解决办法很简单,由于O0和O1坐标已经确定下来了,故这两点所在直线的斜率也有了,再已知车高H,车宽W(图中未标识),这样就可以得到同侧的四个点坐标,将这四个点坐标沿着Z方向平移即可得车体的八个点顶点坐标。

    下面是计算过程:

    假设后轮圆心所在坐标为O0(x0,y0),后轮的同侧车顶坐标为T(x1,y1),K0为O0点与O1点所在直线的斜率,K1为O0点与T点所在直线的斜率,有:

    同理,前轮的同侧顶部坐标也能计算得出。

    使用c++代码实现如下(实现所用的变量名称和假设推理的不一样):

    /* 
    点集顺序如下
    1-----------4
    |			|
    2-----------3
    */
    void get_car_coordinate(CC3DPoint &_point2, CC3DPoint &_point3, float _height, CC3DPoint &_point1, CC3DPoint &_point4){
    	float k0, k1, cos_alpha, sin_alpha;
    	
    	k0 = (_point3.y - _point2.y) / (_point3.x - _point2.x);
    	
    	if (k0 == 0.0){
    		_point1.x = _point2.x;
    		_point1.y = _point2.y + _height;
    		_point1.z = _point2.z;
    
    		_point4.x = _point3.x;
    		_point4.y = _point3.y + _height;
    		_point4.z = _point3.z;
    		return;
    	}
    
    	k1 = -1 / k0;
    
    	cos_alpha = sqrt(1 / ((k1 * k1) + 1));
    
    	sin_alpha = sqrt((k1 * k1) / (1 + k1*k1));
    
    	_point1.y = _point2.y + _height * sin_alpha;
    	_point4.y = _point3.y + _height * sin_alpha;
    
    	_point1.z = _point2.z;
    	_point4.z = _point2.z;
    
    	if (k0 > 0){
    		_point1.x = _point2.x - _height * cos_alpha;
    		_point4.x = _point3.x - _height * cos_alpha;
    	}
    	else{
    		_point1.x = _point2.x + _height * cos_alpha;
    		_point4.x = _point3.x + _height * cos_alpha;
    	}
    }
    

    根据这四个点绘制的效果如下:

    将这四个坐标沿着Z轴进行平移可得到另一边的四个点,依据这八个点绘得图像可得:

    这样,随着地形起伏的车体也就能够画出来了。


    问题二:如何按照指定位移前进?

    车的移动位移取决于轮子的旋转角度,角度决定着其运动的位移。设轮子每次转动的角度为θ,则轮子转动θ向前行进的路程s=θ/360*2πR,R为轮子半径。但地形不是直线,而是曲线,故要想车实际运动的路程等于s,则需要对地形曲线做积分计算,计算过程如下:

    在已知了旋转角度θ的情况下,有两种思路可供解决这个问题:

    1. 对曲线上的点进行距离累加计算,直到累加的距离大于s。

    2. 对曲线弧进行第一类曲线积分计算。

    针对于第一种方法:

    其就是分段求距离,化曲为直。

    	//s : 为指定路程;_search_inc: 为递增变量;_x : 搜索起始;
    	// 累加的距离和
    	float sum = 0.0f;
    	// 前一个参考坐标
    	float x0 = _x, y0 = f(x0);
    	// 递增坐标
    	float tmp_x = x0, tmp_y = 0.0f;
    	// 当前计算距离
    	float dis = 0.0f;
    	while (true){
    		tmp_x += _search_inc;
    		tmp_y = f(tmp_x);
    
    		dis = dis_between_points(x0, y0, tmp_x, tmp_y);
    		x0 = tmp_x;
    		y0 = tmp_y;
    		sum += dis;
    
    		if (sum >= s){
    			// Already saved by _offset_x.
    			return;
    		}
    		else{
    			_offset_x = tmp_x;
    		}
    	}
    

    针对第二种方法:

    根据第一类曲线积分的方法可得:

    	float tmp_x = _x, sum = 0.0f, dx = _search_inc;
    	while (sum < s) {
    		tmp_x += dx;
    		sum += sqrt(1 + pow(derived_f(tmp_x), 2)) * abs(dx);
    	}
    	fprintf(stdout, "test_x : %lf
    ", tmp_x);
    

    关于这两种方法的比较:

    • 第一种需要计算累计距离,而每次计算的差值都→0,故由于机器浮点数计算而产生的误差会累积,而且计算量大。

    • 第二种基于积分的计算,其本意是用积分计算积分,也存在计算的误差但是相比第一种的在直接机器计算上要小得多,计算量小。

    • 我会使用第二种,理由是代码简短,基于优美的数学公式。

    如此,在设定了轮子旋转角度的情况下,接着计算在曲线上的长度对应的x方向位移,使之画出一个轮子。


    总结:

    • 根据前一篇文章和这篇文章,总结了小车在简单已知地形上的运动轨迹。

    • 但是这种小车的局限性实在是太大了,只能在x方向前后移动,而且地形函数十分简单,或者说不太复杂。

    • 我还见识到了数值计算的力量,很多时候精确解并不是一件轻松的事情,可以尝试换个角度,使用近似解,照样可以达到满意的效果。

    • 感觉还是学的太少,有些思维还是太局限,得继续学习与努力。


    Thanks

    提供在线的公式编辑

    提供在线的函数绘制

    Markdownpad

    3/31/2017 11:05:41 PM

  • 相关阅读:
    vue-fullcalendar插件
    iframe 父框架调用子框架的函数
    关于调试的一点感想
    hdfs 删除和新增节点
    hadoop yarn 实战错误汇总
    Ganglia 安装 No package 'ck' found
    storm on yarn(CDH5) 部署笔记
    spark on yarn 安装笔记
    storm on yarn安装时 提交到yarn失败 failed
    yarn storm spark
  • 原文地址:https://www.cnblogs.com/leihui/p/6654016.html
Copyright © 2011-2022 走看看