最近在写一个数值计算数学软件,用于矩阵分析、线性、非线性方程(组)求解、数值积分的求解,二维、三维绘图。
其中的三维绘图,用OpenGl渲染,本来打算用原生的方法实现,但是能力有限,且对OpenGl不太熟悉,就直接用java实现啦。效率还行。
实现机制是:先传入空间几何体的方程 (z=f(x,y)、x=u(t),y=v(t),z=w(t)) 其中包括显示方程和参数方程。以及变量x y的取值范围。在绘制的时候,对x y进行 分割 ,取相邻的四个点组成两个三角形进行绘制.具体代码如下:
1.
package com.example.plot;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
public class MySurefaceView extends GLSurfaceView
{
private final float SUO=180.f/320 ;//缩放比例
private SceneRenderer mRenderer ;
private float shangX ;
private float shangY ;
public MySurefaceView(Context context)
{
super(context);
mRenderer=new SceneRenderer();
setRenderer(mRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY) ;//设置为主动渲染
}
//触摸事件
@Override
public boolean onTouchEvent(MotionEvent event)
{
float x=event.getX();
float y=event.getY() ;
if(event.getAction()==MotionEvent.ACTION_MOVE)
{
float dx=x-shangX ;
float dy=y-shangY ;
mRenderer.funcView.angleY+=dx*SUO ;
mRenderer.funcView.angleZ+=dy*SUO ;
requestRender() ;
}
shangX=x ;
shangY=y ;
return true;
}
private class SceneRenderer implements Renderer ,IFunc
{
FuncView funcView ;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
gl.glDisable(GL10.GL_DITHER) ;// 闭关抗抖动
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST) ;
gl.glClearColor(0, 0, 0, 0) ;
gl.glShadeModel(GL10.GL_SMOOTH) ;//平滑着色
gl.glEnable(GL10.GL_DEPTH_TEST) ;//深度测试
gl.glColor4f(1, 0, 0, 1);
funcView=new FuncView(-1, 1, 0, 2*Math.PI,this) ; //实例画 传入x y的范围和方程函数接口
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION) ;// 设置当前矩阵为投影矩阵
gl.glLoadIdentity() ; //设置当前矩阵为单位矩阵
float ratio=(float)width/height;
gl.glFrustumf(-ratio, ratio, -0.5f, 1.5f, 1, 100) ; //调用次方法计算产生透视投影矩阵
// gl.glOrthof(-ratio, ratio, -0.5f, 1.5f, 1, 100) ; //产生正交投影矩阵
// GLU.gluLookAt(gl,-1.0f,0.6f,3.0f,1.3f,-2.4f,2f,0f,1.0f,0.0f);
}
@Override
public void onDrawFrame(GL10 gl)
{
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);// 清楚颜色缓存
gl.glMatrixMode(GL10.GL_MODELVIEW);//设置为矩阵模式
gl.glLoadIdentity() ;
gl.glPushMatrix() ;
gl.glTranslatef(0, 0, -4f);
funcView.draw(gl);
gl.glPopMatrix() ;
}
//传入的方程
@Override
public float getX(double x, double y)
{
return (float) x;
}
@Override
public float getY(double x, double y)
{
return (float)( Math.pow(Math.E, -(x*Math.cos(4*x))*(x*Math.cos(4*x)))*Math.cos(y));
}
@Override
public float getZ(double x, double y)
{
return (float)( Math.pow(Math.E, -(x*Math.cos(4*x))*(x*Math.cos(4*x)))*Math.sin(y));
}
}
}
2.分割和绘制代码
package com.example.plot;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import javax.microedition.khronos.opengles.GL10;
public class FuncView
{
public float angleX;
public float angleY;
public float angleZ;
private int vCount=0; //顶点个数
private FloatBuffer vBuf;
// f(z)=cos(x)-x*sin(x) x[0,2pi] y[0,2pi]
public FuncView(double xLow,double xHeight,double yLow,double yHeight,IFunc func)
{
double stepX = (xHeight-xLow)/100 ;
double stepY=(yHeight-yLow)/100 ;
ArrayList<Float> val=new ArrayList<Float>(); //存放顶点的列表
float x=(float) xLow ;
float y=(float) yLow ;
for (int i = 0; i <=100; i++, x += stepX)
{
for (int j = 0; j <= 100; j++, y += stepY)
{
float x1= func.getX(x, y) ;
float y1= func.getY(x, y) ;
float z1= func.getZ(x, y) ;
float x2= func.getX(x+stepX, y) ;
float y2= func.getY(x+stepX, y) ;
float z2= func.getZ(x+stepX, y) ;
float x3= func.getX(x+stepX, y+stepY) ;
float y3= func.getY(x+stepX, y+stepY) ;
float z3= func.getZ(x+stepX, y+stepY) ;
float x4= func.getX(x, y+stepY) ;
float y4= func.getY(x, y+stepY) ;
float z4= func.getZ(x, y+stepY) ;
val.add(x1) ;val.add(y1) ;val.add(z1) ;
val.add(x2) ;val.add(y2) ;val.add(z2) ;
val.add(x4) ;val.add(y4) ;val.add(z4) ;
val.add(x2) ;val.add(y2) ;val.add(z2) ;
val.add(x3) ;val.add(y3) ;val.add(z3) ;
val.add(x4) ;val.add(y4) ;val.add(z4) ;
}
}
vCount=val.size()/3 ;
float[] vertexs = new float[vCount*3]; //存放顶点数据
for(int i=0;i<vCount;i++)
{
vertexs[i*3]=val.get(i*3);
vertexs[i*3+1]=val.get(i*3+1);
vertexs[i*3+2]=val.get(i*3+2);
}
ByteBuffer vbb;
vbb = ByteBuffer.allocateDirect(vertexs.length * 4);
vbb.order(ByteOrder.nativeOrder());
vBuf = vbb.asFloatBuffer();
vBuf.put(vertexs);
vBuf.position(0);
}
public void draw(GL10 gl)
{
gl.glRotatef(angleX, 1, 0, 0);
gl.glRotatef(angleY, 0, 1, 0);
gl.glRotatef(angleZ, 0, 0, 1);
gl.glScalef(0.8F, 0.8F, 0.8F) ;
gl.glRotatef(-90, 1, 0, 0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vBuf);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vCount);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
3.方程接口
package com.example.plot;
public interface IFunc
{
public float getX(double x,double y) ;
public float getY(double x,double y) ;
public float getZ(double x,double y) ;
}
4.主Activity
package com.example.plot;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
public class MainActivity extends ActionBarActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(new MySurefaceView(this));
}
}