Android 吸入动画效果实现分解

时间:2022-03-03 07:40:56

android 吸入动画效果详解 .
Android 吸入动画效果实现分解 
这里,我要介绍的是如何在android上面实现一个类似的效果。先看看我实现的效果图。
Android 吸入动画效果实现分解 
上图演示了动画的某几帧,其中从1 - 4,演示了图片从原始图形吸入到一个点(红色标识)。
实现这样的效果,我们利用了canvas.drawbitmapmesh()方法,这里涉及到了一个mesh的概念。
2,mesh的概念
mesh表示网格,说得通俗一点,可以将画板想像成一张格子布,在这个张布上绘制图片。对于一个网格端点均匀分布的网格来说,横向有meshwidth + 1个顶点,纵向有meshheight + 1个端点。顶点数据verts是以行优先的数组(二维数组以一维数组表示,先行后列)。网格可以不均匀分布。请看下图所示:
Android 吸入动画效果实现分解 
上图中显示了把图片分成很多格子,上图中的每个格子是均匀的,它的顶点数是:(meshwidth + 1) * (meshheight + 1)个,那么放这些顶点的一维数据的大小应该是:(meshwidth + 1) * (meshheight + 1) * 2 (一个点包含x, y坐标)

复制代码 代码如下:


float[] vertices = new float[:(meshwidth + 1) * (meshheight + 1) * 2];


试想,我们让这个格子(mesh)不均匀分布,那么绘制出来的图片就会变形,请看下图所示:
Android 吸入动画效果实现分解 
3,如何构建mesh
吸入动画的核心是吸入到一个点,那么我们就是要在不同的时刻构造出不同的mesh的顶点坐标,我们是怎么做的呢?
3.1,创建两条路径(path)
假如我们的吸入效果是从上到下吸入,我们构造的path是如下图所示:
Android 吸入动画效果实现分解 
上图中蓝色的线表示我们构造的path,其实只要我们沿着这两条path来构造mesh顶点就可以了。
构建两条path的代码如下:

复制代码 代码如下:


mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
float w = mbmpwidth;
float h = mbmpheight;
mfirstpath.reset();
msecondpath.reset();
mfirstpath.moveto(0, 0);
msecondpath.moveto(w, 0);
mfirstpath.lineto(0, h);
msecondpath.lineto(w, h);
mfirstpath.quadto(0, (endy + h) / 2, endx, endy);
msecondpath.quadto(w, (endy + h) / 2, endx, endy);


3.2,根据path来计算顶点坐标
算法:
1,假如我们把格子分为width, height份,把path的长度分的20份,[0, length],表示20个时刻。
2,第0时间,我们要的形状是一个矩形,第1时刻可能是梯形,第n时间可能是一个三角形。下图说明了动画过程中图片的变化。
Android 吸入动画效果实现分解 
3,第一条(左)path的长度为len1,第二条(右)path的长度为len2,对于任意时刻 t [0 - 20],我们可以知道梯形的四个顶点距path最顶端的length。
左上角:t * (len1 / 20)
左下角:t * (len1 / 20) + bitmapheight
右上角:t * (len2 / 20)
右下角:t * (len2 / 20) + bitmapheight
Android 吸入动画效果实现分解 
我们可以通过pathmeasure类根据length算出在path上面点的坐标,也就是说,根据两条path,我们可以分别算了四个顶点的坐标,我这里分别叫做a, b, c, d(顺时针方向),有了点的坐标,我们可以算出ad,bc的长度,并且将基进行height等分(因为我们把mesh分成宽width,高height等分),将ad,bc上面每等分的点连接起来形成一条直接,将再这条直接水平width等分,根据直线方程,依据x算出y,从而算出每一个顶点的坐标。(请参考上图)
下面是计算顶点坐标的详细代码:

复制代码 代码如下:


private void buildmeshbypathonvertical(int timeindex)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
int index = 0;
float[] pos1 = {0.0f, 0.0f};
float[] pos2 = {0.0f, 0.0f};
float firstlen = mfirstpathmeasure.getlength();
float secondlen = msecondpathmeasure.getlength();
float len1 = firstlen / height;
float len2 = secondlen / height;
float firstpointdist = timeindex * len1;
float secondpointdist = timeindex * len2;
float height = mbmpheight;
mfirstpathmeasure.getpostan(firstpointdist, pos1, null);
mfirstpathmeasure.getpostan(firstpointdist + height, pos2, null);
float x1 = pos1[0];
float x2 = pos2[0];
float y1 = pos1[1];
float y2 = pos2[1];
float first_dist = (float)math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
float first_h = first_dist / height;
msecondpathmeasure.getpostan(secondpointdist, pos1, null);
msecondpathmeasure.getpostan(secondpointdist + height, pos2, null);
x1 = pos1[0];
x2 = pos2[0];
y1 = pos1[1];
y2 = pos2[1];
float second_dist = (float)math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
float second_h = second_dist / height;
for (int y = 0; y <= height; ++y)
{
mfirstpathmeasure.getpostan(y * first_h + firstpointdist, pos1, null);
msecondpathmeasure.getpostan(y * second_h + secondpointdist, pos2, null);
float w = pos2[0] - pos1[0];
float fx1 = pos1[0];
float fx2 = pos2[0];
float fy1 = pos1[1];
float fy2 = pos2[1];
float dy = fy2 - fy1;
float dx = fx2 - fx1;
for (int x = 0; x <= width; ++x)
{
// y = x * dy / dx
float fx = x * w / width;
float fy = fx * dy / dx;
mverts[index * 2 + 0] = fx + fx1;
mverts[index * 2 + 1] = fy + fy1;
index += 1;
}
}
}


4,如何绘制
绘制代码很简单,调用canvas.drawbitmapmesh方法。最本质是要计算出一个顶点数组。

复制代码 代码如下:


canvas.drawbitmapmesh(mbitmap,
minhalemesh.getwidth(),
minhalemesh.getheight(),
minhalemesh.getvertices(),
0, null, 0, mpaint);


5,如何实现动画

复制代码 代码如下:


protected void applytransformation(float interpolatedtime, transformation t)
{
int curindex = 0;
interpolator interpolator = this.getinterpolator();
if (null != interpolator)
{
float value = interpolator.getinterpolation(interpolatedtime);
interpolatedtime = value;
}
if (mreverse)
{
interpolatedtime = 1.0f - interpolatedtime;
}
curindex = (int)(mfromindex + (mendindex - mfromindex) * interpolatedtime);
if (null != mlistener)
{
mlistener.onanimupdate(curindex);
}
}


在动画里面,我们计算出要做动画的帧的index,假设我们把吸入动画分为20帧,在动画里面,计算出每一帧,最后通过onanimupdate(int index)方法回调,在这个方法实现里面,我们根据帧的index来重新计算一个新的mesh顶点数组,再用这个数组来绘制bitmap。这样,我们就可以看来一组连续变化的mesh,也就能看到吸扩效果的动画。
动画类里面,最核心就是扩展animation类,重写applytransformation方法。
6,总结
本文简单介绍了吸放效果的实现,根据这个原理,我们可以构造更加复杂的path来做更多的效果。同时,也能实现向上,向左,向右的吸入效果。
最本质是我们要理解mesh的概念,最核心的工作就是构造出mesh的顶点坐标。
计算mesh通常是一个很复杂的工作,作一些简单的变形还可以,对于太复杂的变形,可能还是不太方便。另外,像书籍翻页的效果,用mesh其实也是可以做到的。只是算法复杂一点。
这里不能给出完整的代码,原理可能不是说得太清楚,但愿给想实现的人一个思路指引吧。
7,实现代码
inhaleanimationactivity.java

复制代码 代码如下:


package com.nj1s.lib.test.anim;
import android.os.bundle;
import android.view.gravity;
import android.view.menu;
import android.view.menuitem;
import android.view.view;
import android.widget.button;
import android.widget.linearlayout;
import com.nj1s.lib.mesh.inhalemesh.inhaledir;
import com.nj1s.lib.test.gabaseactivity;
import com.nj1s.lib.test.r;
import com.nj1s.lib.test.effect.bitmapmesh;
public class inhaleanimationactivity extends gabaseactivity
{
private static final boolean debug_mode = false;
private bitmapmesh.sampleview msampleview = null;
@override
protected void oncreate(bundle savedinstancestate)
{
super.oncreate(savedinstancestate);
linearlayout linearlayout = new linearlayout(this);
msampleview = new bitmapmesh.sampleview(this);
msampleview.setisdebug(debug_mode);
msampleview.setlayoutparams(new linearlayout.layoutparams(-1, -1));
button btn = new button(this);
btn.settext("run");
btn.settextsize(20.0f);
btn.setlayoutparams(new linearlayout.layoutparams(150, -2));
btn.setonclicklistener(new view.onclicklistener()
{
boolean mreverse = false;
@override
public void onclick(view v)
{
if (msampleview.startanimation(mreverse))
{
mreverse = !mreverse;
}
}
});
linearlayout.setorientation(linearlayout.vertical);
linearlayout.setgravity(gravity.center_vertical);
linearlayout.addview(btn);
linearlayout.addview(msampleview);
setcontentview(linearlayout);
}
@override
public boolean oncreateoptionsmenu(menu menu)
{
getmenuinflater().inflate(r.menu.inhale_anim_menu, menu);
return true;
}
@override
public boolean onoptionsitemselected(menuitem item)
{
switch(item.getitemid())
{
case r.id.menu_inhale_down:
msampleview.setinhaledir(inhaledir.down);
break;
case r.id.menu_inhale_up:
msampleview.setinhaledir(inhaledir.up);
break;
case r.id.menu_inhale_left:
msampleview.setinhaledir(inhaledir.left);
break;
case r.id.menu_inhale_right:
msampleview.setinhaledir(inhaledir.right);
break;
}
return super.onoptionsitemselected(item);
}
}


bitmapmesh.java

复制代码 代码如下:


/*
* copyright (c) 2008 the android open source project
*
* licensed under the apache license, version 2.0 (the "license");
* you may not use this file except in compliance with the license.
* you may obtain a copy of the license at
*
* http://www.apache.org/licenses/license-2.0
*
* unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "as is" basis,
* without warranties or conditions of any kind, either express or implied.
* see the license for the specific language governing permissions and
* limitations under the license.
*/
package com.nj1s.lib.test.effect;
import android.content.context;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.matrix;
import android.graphics.paint;
import android.graphics.paint.style;
import android.graphics.path;
import android.util.log;
import android.view.motionevent;
import android.view.view;
import android.view.animation.animation;
import android.view.animation.interpolator;
import android.view.animation.transformation;
import com.nj1s.lib.mesh.inhalemesh;
import com.nj1s.lib.mesh.inhalemesh.inhaledir;
import com.nj1s.lib.test.r;
public class bitmapmesh {
public static class sampleview extends view {
private static final int width = 40;
private static final int height = 40;
private final bitmap mbitmap;
private final matrix mmatrix = new matrix();
private final matrix minverse = new matrix();
private boolean misdebug = false;
private paint mpaint = new paint();
private float[] minhalept = new float[] {0, 0};
private inhalemesh minhalemesh = null;
public sampleview(context context) {
super(context);
setfocusable(true);
mbitmap = bitmapfactory.decoderesource(getresources(),
r.drawable.beach);
minhalemesh = new inhalemesh(width, height);
minhalemesh.setbitmapsize(mbitmap.getwidth(), mbitmap.getheight());
minhalemesh.setinhaledir(inhaledir.down);
}
public void setisdebug(boolean isdebug)
{
misdebug = isdebug;
}
public void setinhaledir(inhalemesh.inhaledir dir)
{
minhalemesh.setinhaledir(dir);
float w = mbitmap.getwidth();
float h = mbitmap.getheight();
float endx = 0;
float endy = 0;
float dx = 10;
float dy = 10;
mmatrix.reset();
switch (dir)
{
case down:
endx = w / 2;
endy = getheight() - 20;
break;
case up:
dy = getheight() - h - 20;
endx = w / 2;
endy = -dy + 10;
break;
case left:
dx = getwidth() - w - 20;
endx = -dx + 10;
endy = h / 2;
break;
case right:
endx = getwidth() - 20;
endy = h / 2;
break;
}
mmatrix.settranslate(dx, dy);
mmatrix.invert(minverse);
buildpaths(endx, endy);
buildmesh(w, h);
invalidate();
}
@override
protected void onsizechanged(int w, int h, int oldw, int oldh)
{
super.onsizechanged(w, h, oldw, oldh);
float bmpw = mbitmap.getwidth();
float bmph = mbitmap.getheight();
mmatrix.settranslate(10, 10);
//mmatrix.settranslate(10, 10);
mmatrix.invert(minverse);
mpaint.setcolor(color.red);
mpaint.setstrokewidth(2);
mpaint.setantialias(true);
buildpaths(bmpw / 2, h - 20);
buildmesh(bmpw, bmph);
}
public boolean startanimation(boolean reverse)
{
animation anim = this.getanimation();
if (null != anim && !anim.hasended())
{
return false;
}
pathanimation animation = new pathanimation(0, height + 1, reverse,
new pathanimation.ianimationupdatelistener()
{
@override
public void onanimupdate(int index)
{
minhalemesh.buildmeshes(index);
invalidate();
}
});
if (null != animation)
{
animation.setduration(1000);
this.startanimation(animation);
}
return true;
}
@override
protected void ondraw(canvas canvas)
{
log.i("leehong2", "ondraw =========== ");
canvas.drawcolor(0xffcccccc);
canvas.concat(mmatrix);
canvas.drawbitmapmesh(mbitmap,
minhalemesh.getwidth(),
minhalemesh.getheight(),
minhalemesh.getvertices(),
0, null, 0, mpaint);
// ===========================================
// draw the target point.
mpaint.setcolor(color.red);
mpaint.setstyle(style.fill);
canvas.drawcircle(minhalept[0], minhalept[1], 5, mpaint);
if (misdebug)
{
// ===========================================
// draw the mesh vertices.
canvas.drawpoints(minhalemesh.getvertices(), mpaint);
// ===========================================
// draw the paths
mpaint.setcolor(color.blue);
mpaint.setstyle(style.stroke);
path[] paths = minhalemesh.getpaths();
for (path path : paths)
{
canvas.drawpath(path, mpaint);
}
}
}
private void buildmesh(float w, float h)
{
minhalemesh.buildmeshes(w, h);
}
private void buildpaths(float endx, float endy)
{
minhalept[0] = endx;
minhalept[1] = endy;
minhalemesh.buildpaths(endx, endy);
}
int mlastwarpx = 0;
int mlastwarpy = 0;
@override
public boolean ontouchevent(motionevent event)
{
float[] pt = { event.getx(), event.gety() };
minverse.mappoints(pt);
if (event.getaction() == motionevent.action_up)
{
int x = (int)pt[0];
int y = (int)pt[1];
if (mlastwarpx != x || mlastwarpy != y) {
mlastwarpx = x;
mlastwarpy = y;
buildpaths(pt[0], pt[1]);
invalidate();
}
}
return true;
}
}
private static class pathanimation extends animation
{
public interface ianimationupdatelistener
{
public void onanimupdate(int index);
}
private int mfromindex = 0;
private int mendindex = 0;
private boolean mreverse = false;
private ianimationupdatelistener mlistener = null;
public pathanimation(int fromindex, int endindex, boolean reverse, ianimationupdatelistener listener)
{
mfromindex = fromindex;
mendindex = endindex;
mreverse = reverse;
mlistener = listener;
}
public boolean gettransformation(long currenttime, transformation outtransformation) {
boolean more = super.gettransformation(currenttime, outtransformation);
log.d("leehong2", "gettransformation more = " + more);
return more;
}
@override
protected void applytransformation(float interpolatedtime, transformation t)
{
int curindex = 0;
interpolator interpolator = this.getinterpolator();
if (null != interpolator)
{
float value = interpolator.getinterpolation(interpolatedtime);
interpolatedtime = value;
}
if (mreverse)
{
interpolatedtime = 1.0f - interpolatedtime;
}
curindex = (int)(mfromindex + (mendindex - mfromindex) * interpolatedtime);
if (null != mlistener)
{
log.i("leehong2", "onanimupdate =========== curindex = " + curindex);
mlistener.onanimupdate(curindex);
}
}
}
}


最核心的类
inhalemesh

复制代码 代码如下:


package com.nj1s.lib.mesh;
import android.graphics.path;
import android.graphics.pathmeasure;
public class inhalemesh extends mesh
{
public enum inhaledir
{
up,
down,
left,
right,
}
private path mfirstpath = new path();
private path msecondpath = new path();
private pathmeasure mfirstpathmeasure = new pathmeasure();
private pathmeasure msecondpathmeasure = new pathmeasure();
private inhaledir minhaledir = inhaledir.down;
public inhalemesh(int width, int height)
{
super(width, height);
}
public void setinhaledir(inhaledir inhaledir)
{
minhaledir = inhaledir;
}
public inhaledir getinhaledir()
{
return minhaledir;
}
@override
public void buildpaths(float endx, float endy)
{
if (mbmpwidth <= 0 || mbmpheight <= 0)
{
throw new illegalargumentexception(
"bitmap size must be > 0, do you call setbitmapsize(int, int) method?");
}
switch (minhaledir)
{
case up:
buildpathsup(endx, endy);
break;
case down:
buildpathsdown(endx, endy);
break;
case right:
buildpathsright(endx, endy);
break;
case left:
buildpathsleft(endx, endy);
break;
}
}
@override
public void buildmeshes(int index)
{
if (mbmpwidth <= 0 || mbmpheight <= 0)
{
throw new illegalargumentexception(
"bitmap size must be > 0, do you call setbitmapsize(int, int) method?");
}
switch (minhaledir)
{
case up:
case down:
buildmeshbypathonvertical(index);
break;
case right:
case left:
buildmeshbypathonhorizontal(index);
break;
}
}
public path[] getpaths()
{
return new path[] { mfirstpath, msecondpath };
}
private void buildpathsdown(float endx, float endy)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
float w = mbmpwidth;
float h = mbmpheight;
mfirstpath.reset();
msecondpath.reset();
mfirstpath.moveto(0, 0);
msecondpath.moveto(w, 0);
mfirstpath.lineto(0, h);
msecondpath.lineto(w, h);
mfirstpath.quadto(0, (endy + h) / 2, endx, endy);
msecondpath.quadto(w, (endy + h) / 2, endx, endy);
}
private void buildpathsup(float endx, float endy)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
float w = mbmpwidth;
float h = mbmpheight;
mfirstpath.reset();
msecondpath.reset();
mfirstpath.moveto(0, h);
msecondpath.moveto(w, h);
mfirstpath.lineto(0, 0);
msecondpath.lineto(w, 0);
mfirstpath.quadto(0, (endy - h) / 2, endx, endy);
msecondpath.quadto(w, (endy - h) / 2, endx, endy);
}
private void buildpathsright(float endx, float endy)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
float w = mbmpwidth;
float h = mbmpheight;
mfirstpath.reset();
msecondpath.reset();
mfirstpath.moveto(0, 0);
msecondpath.moveto(0, h);
mfirstpath.lineto(w, 0);
msecondpath.lineto(w, h);
mfirstpath.quadto((endx + w) / 2, 0, endx, endy);
msecondpath.quadto((endx + w) / 2, h, endx, endy);
}
private void buildpathsleft(float endx, float endy)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
float w = mbmpwidth;
float h = mbmpheight;
mfirstpath.reset();
msecondpath.reset();
mfirstpath.moveto(w, 0);
msecondpath.moveto(w, h);
mfirstpath.lineto(0, 0);
msecondpath.lineto(0, h);
mfirstpath.quadto((endx - w) / 2, 0, endx, endy);
msecondpath.quadto((endx - w) / 2, h, endx, endy);
}
private void buildmeshbypathonvertical(int timeindex)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
int index = 0;
float[] pos1 = {0.0f, 0.0f};
float[] pos2 = {0.0f, 0.0f};
float firstlen = mfirstpathmeasure.getlength();
float secondlen = msecondpathmeasure.getlength();
float len1 = firstlen / height;
float len2 = secondlen / height;
float firstpointdist = timeindex * len1;
float secondpointdist = timeindex * len2;
float height = mbmpheight;
mfirstpathmeasure.getpostan(firstpointdist, pos1, null);
mfirstpathmeasure.getpostan(firstpointdist + height, pos2, null);
float x1 = pos1[0];
float x2 = pos2[0];
float y1 = pos1[1];
float y2 = pos2[1];
float first_dist = (float)math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
float first_h = first_dist / height;
msecondpathmeasure.getpostan(secondpointdist, pos1, null);
msecondpathmeasure.getpostan(secondpointdist + height, pos2, null);
x1 = pos1[0];
x2 = pos2[0];
y1 = pos1[1];
y2 = pos2[1];
float second_dist = (float)math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
float second_h = second_dist / height;
if (minhaledir == inhaledir.down)
{
for (int y = 0; y <= height; ++y)
{
mfirstpathmeasure.getpostan(y * first_h + firstpointdist, pos1, null);
msecondpathmeasure.getpostan(y * second_h + secondpointdist, pos2, null);
float w = pos2[0] - pos1[0];
float fx1 = pos1[0];
float fx2 = pos2[0];
float fy1 = pos1[1];
float fy2 = pos2[1];
float dy = fy2 - fy1;
float dx = fx2 - fx1;
for (int x = 0; x <= width; ++x)
{
// y = x * dy / dx
float fx = x * w / width;
float fy = fx * dy / dx;
mverts[index * 2 + 0] = fx + fx1;
mverts[index * 2 + 1] = fy + fy1;
index += 1;
}
}
}
else if (minhaledir == inhaledir.up)
{
for (int y = height; y >= 0; --y)
{
mfirstpathmeasure.getpostan(y * first_h + firstpointdist, pos1, null);
msecondpathmeasure.getpostan(y * second_h + secondpointdist, pos2, null);
float w = pos2[0] - pos1[0];
float fx1 = pos1[0];
float fx2 = pos2[0];
float fy1 = pos1[1];
float fy2 = pos2[1];
float dy = fy2 - fy1;
float dx = fx2 - fx1;
for (int x = 0; x <= width; ++x)
{
// y = x * dy / dx
float fx = x * w / width;
float fy = fx * dy / dx;
mverts[index * 2 + 0] = fx + fx1;
mverts[index * 2 + 1] = fy + fy1;
index += 1;
}
}
}
}
private void buildmeshbypathonhorizontal(int timeindex)
{
mfirstpathmeasure.setpath(mfirstpath, false);
msecondpathmeasure.setpath(msecondpath, false);
int index = 0;
float[] pos1 = {0.0f, 0.0f};
float[] pos2 = {0.0f, 0.0f};
float firstlen = mfirstpathmeasure.getlength();
float secondlen = msecondpathmeasure.getlength();
float len1 = firstlen / width;
float len2 = secondlen / width;
float firstpointdist = timeindex * len1;
float secondpointdist = timeindex * len2;
float width = mbmpwidth;
mfirstpathmeasure.getpostan(firstpointdist, pos1, null);
mfirstpathmeasure.getpostan(firstpointdist + width, pos2, null);
float x1 = pos1[0];
float x2 = pos2[0];
float y1 = pos1[1];
float y2 = pos2[1];
float first_dist = (float)math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
float first_x = first_dist / width;
msecondpathmeasure.getpostan(secondpointdist, pos1, null);
msecondpathmeasure.getpostan(secondpointdist + width, pos2, null);
x1 = pos1[0];
x2 = pos2[0];
y1 = pos1[1];
y2 = pos2[1];
float second_dist = (float)math.sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
float second_x = second_dist / width;
if (minhaledir == inhaledir.right)
{
for (int x = 0; x <= width; ++x)
{
mfirstpathmeasure.getpostan(x * first_x + firstpointdist, pos1, null);
msecondpathmeasure.getpostan(x * second_x + secondpointdist, pos2, null);
float h = pos2[1] - pos1[1];
float fx1 = pos1[0];
float fx2 = pos2[0];
float fy1 = pos1[1];
float fy2 = pos2[1];
float dy = fy2 - fy1;
float dx = fx2 - fx1;
for (int y = 0; y <= height; ++y)
{
// x = y * dx / dy
float fy = y * h / height;
float fx = fy * dx / dy;
index = y * (width + 1) + x;
mverts[index * 2 + 0] = fx + fx1;
mverts[index * 2 + 1] = fy + fy1;
}
}
}
else if (minhaledir == inhaledir.left)
{
for (int x = width; x >= 0; --x)
//for (int x = 0; x <= width; ++x)
{
mfirstpathmeasure.getpostan(x * first_x + firstpointdist, pos1, null);
msecondpathmeasure.getpostan(x * second_x + secondpointdist, pos2, null);
float h = pos2[1] - pos1[1];
float fx1 = pos1[0];
float fx2 = pos2[0];
float fy1 = pos1[1];
float fy2 = pos2[1];
float dy = fy2 - fy1;
float dx = fx2 - fx1;
for (int y = 0; y <= height; ++y)
{
// x = y * dx / dy
float fy = y * h / height;
float fx = fy * dx / dy;
index = y * (width + 1) + width - x;
mverts[index * 2 + 0] = fx + fx1;
mverts[index * 2 + 1] = fy + fy1;
}
}
}
}
}


mesh类的实现

复制代码 代码如下:


/*
* system: corelib
* @version 1.00
*
* copyright (c) 2010, lzt corporation.
*
*/
package com.nj1s.lib.mesh;
public abstract class mesh
{
protected int width = 40;
protected int height = 40;
protected int mbmpwidth = -1;
protected int mbmpheight = -1;
protected final float[] mverts;
public mesh(int width, int height)
{
width = width;
height = height;
mverts = new float[(width + 1) * (height + 1) * 2];
}
public float[] getvertices()
{
return mverts;
}
public int getwidth()
{
return width;
}
public int getheight()
{
return height;
}
public static void setxy(float[] array, int index, float x, float y)
{
array[index*2 + 0] = x;
array[index*2 + 1] = y;
}
public void setbitmapsize(int w, int h)
{
mbmpwidth = w;
mbmpheight = h;
}
public abstract void buildpaths(float endx, float endy);
public abstract void buildmeshes(int index);
public void buildmeshes(float w, float h)
{
int index = 0;
for (int y = 0; y <= height; ++y)
{
float fy = y * h / height;
for (int x = 0; x <= width; ++x)
{
float fx = x * w / width;
setxy(mverts, index, fx, fy);
index += 1;
}
}
}
}