Friday, September 15, 2017

行星系坐标变换 和 一些 OPENGL的感悟

这个例子是地球绕太阳,月亮同时绕地球的渲染

1.太阳为原点渲染,地球的坐标先平移,再绕原点y轴旋转渲染
2.麻烦的是月亮。月亮的坐标上传后也以原点为中心(big bang模式!opengl的模型上传之后,其局部坐标和世界坐标是重合的,后续的变换都是在世界坐标系中进行的!就像宇宙形成一样从中心大爆炸!)


    1)月亮变换第一种方法:先缩放,然后偏移(偏移距离是月亮距离原点(即太阳)的绝对距离),然后进行坐标系变换,将此时的坐标(在太阳坐标系中给出)变换到地球坐标系中去。由于地球的坐标系是在太阳坐标系的基础上,先旋转再平移得到的(注意两者都有!),所以构建两个view变换矩阵,一个是旋转,一个是平移,月亮的太阳坐标先乘以旋转再乘以平移,得到月亮在地球坐标系里的坐标。(最后为了render,还要将这个坐标变换回太阳坐标系去,同样乘以两个view矩阵,不过和第一步的是相反的方向)。总体是一个世界到local,做完旋转在回到世界的变换过程。

    2) 第二种方法,月亮的坐标先缩放,再偏移,不过此时的偏移量按照相对地球的距离进行。然后做旋转,此时月亮是围绕中心轴以相对地球的偏移在旋转(这些变换都是在太阳坐标系下进行的)。接下来将旋转之后的坐标变换到地球坐标系中去,同样需要一个旋转一个平移变换,得到月亮在地球坐标系的坐标。最后再用两个相反的矩阵将这个坐标变换会太阳坐标系用于render。整体上是一个先在世界坐标系做完旋转(注意此时的旋转半径是月亮相对地球的距离),变换到local坐标,然后再回到世界的过程。

上述变换和在hexapod设计中的坐标变换是类似的(将旋转平台的坐标变换到base坐标系中去,而base坐标系是由旋转坐标系先旋转再平移得到的,所以构建两个view变换矩阵来做变换)

要记住view变换(坐标系变换)和坐标变换之间的关系!

opengl glutPostRedisplay(void)

1用法编辑
void glutPostRedisplay(void);

2描述编辑

glutPostRedisplay 标记当前窗口需要重新绘制。通过glutMainLoop下一次循环时,窗口显示将被回调以重新显示窗口的正常面板。多次调用glutPostRedisplay,在下一个显示回调只产生单一的重新显示回调。
为了便于理解,用下面的例子[1]来说明:
假设有绘制代码:
glutDisplayFunc(display); // opengl drawing goes here
glutTimerFunc(30, drive, -1);// physics, movement equations here
glutMainLoop();
另外有代码如下:
void drive (int data)
{
glutTimerFunc(30, drive, -1);// call drive() again in 30 milliseconds
glutPostRedisplay();
}
如果有glutpostredisplay,mianloop运行的过程会像下面这样:
drive (-1);
display();
drive (-1);
display();
drive (-1);
display();
...
如果没有glutPostRedisplay,glutMainloop运行的过程会像下面这样:
drive (-1);
drive (-1);
drive (-1);
...




Tuesday, July 4, 2017

圆柱度 直线度 和直径公差关系推演


上述例子基于mcmaster的直线圆柱界面导轨数据: 直线度0.001", 直径公差-0.001". 可见该导轨的圆柱度公差还是有可能达到0.002"。

Sunday, July 2, 2017

数据结构与算法--fibonacci的动态规划解法



对比下面这个用一个数组来存储中间变量的方法:以下代码为JAVA:
  1.    /** 
  2.      * 自底向上包含"动态规划"思想的解法 
  3.      * @param n 
  4.      * @return 第n个斐波那契数 
  5.      */  
  6.     public static int downToTopReslove(int n) {  
  7.         if(n == 0) {  
  8.             return 0;  
  9.         } else if(n == 1 || n == 2) {  
  10.             return 1;  
  11.         } else {  
  12.             int[] fibonacciArray = new int[n+1]; //fibonacciArray[i]表示第i个斐波那契数  
  13.             fibonacciArray[0] = 0;  
  14.             fibonacciArray[1] = 1;  
  15.             fibonacciArray[2] = 1;  
  16.             for(int i=3;i<=n;i++) { //注意由于fibonacciArray[0]表示第0个元素,这里是i<=n,而不是i<n  
  17.                 fibonacciArray[i] = fibonacciArray[i-1] + fibonacciArray[i-2];  
  18.             }  
  19.               
  20.             return fibonacciArray[fibonacciArray.length-1];  
  21.         }  
  22.     }  

第一个算法只用了两个中间变量来存储中间值,每次值都会有变化,而第二个方法则是每个中间值都被存储在了对应的数组元素里。

上述两种算法都体现了动态规划的思想。

Sunday, June 18, 2017

halfedge data structure

http://www.holmes3d.net/graphics/dcel/


C++ emplace_back:
https://www.kancloud.cn/wangshubo1989/vector/101113

emplace_back 可以在一个vector中添加一个新的object,这一添加可以免去调用该object的构造函数直接进行。

Monday, June 5, 2017

Cmake to find protobuf on windows

 I also struggled with this. To be more clear.
On Windows (7, similar on older windows): Start --> Control Panel --> System --> Advanced System Settings --> Environment Variables
Then either on the top panel or the bottom panel (if you want it to apply to other users do it on the bottom), create two new variables. The 1st one is
  • CMAKE_INCLUDE_PATH which points at the bottom of your include path (should contain a "google" folder)
  • CMAKE_LIBRARY_PATH which should contain "libprotobuf" "libprotobuf-lite" "liteprotoc" .lib files.
After you create the variables press OK and then re-start cmake (or clean the cache).


每个进程都会有一个返回值的. 
进程开始时是由系统的一个启动函数掉用了main函数的:   
int   nMainRetVal   =   main(); 
当从main函数退出后,启动函数便调用exit函数,并且把nMainRetVa传递给它. 
所以,任何时候都会调用exit函数的,正常情况下,main函数不会调用exit函数的,而是由return   0; 
返回值给nMainRetVal的,exit再接收这个值作为参数的.所以,正常情况下是以exit(0)退出的. 
如果,你程序发生异常,你可以在main函数中调用exit(1),强制退出程序,强制终止进程.其中1表示不正常退出