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


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

    图形学课上的小小总结


    前言

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

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

    前提

    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

  • 相关阅读:
    [luogu8331]简单题
    [luogu8340]山河重整
    [luogu8291]学术社区
    [atARC140E]Not Equal Rectangle
    [luogu8332]面条
    PKUSC2022 总结
    tried accessing the SQLite plugin but Cordova is not available
    Angular安装旧项目的依赖包,运行项目出现异常NullInjectorError: No provider for NzModalService!(环境已升级)
    Angular + ABP前后端分离 登录验证码
    c# RSA加密
  • 原文地址:https://www.cnblogs.com/leihui/p/6654016.html
Copyright © 2020-2023  润新知