在MIDP1.0中实现三角形区域的填充。由于开发的适应性需要,J2ME程序员在很多时候不能使用MIDP2.0进行开发。但是MIDP1.0的功能和2.0相差很多,许多实用的函数都没有提供。这需要程序员自己实现。本文介绍了一个Canvas中的实用的函数,用来在Canvas中填充三角形区域。
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
/*
* Created on 2005-3-30
*
* To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
/**
* @author cuilichen
*
* To change the template for this generated type comment go to Window -
* Preferences - Java - Code Style - Code Templates
*/
public class Triangle extends Canvas {
private Graphics g;
public Triangle(){
}
protected void paint(Graphics arg0) {
g = arg0;
g.setColor(0xffffff);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(0x000000);
Point point0 = new Point(10, 10);
Point point1 = new Point(100, 30);
Point point2 = new Point(200, 160);
long time1 = System.currentTimeMillis();
// for (int i = 0; i < 100; i++)
fillTriangle(point0, point1, point2);
long time2 = System.currentTimeMillis();
System.out.println("time is " + (time2 - time1));
}
/**
* 条件:点point0(x0,y0),point1(x1,y1),point2(x2,y2)组成三角形。 解决办法: 设直线L过point1,point2两个点
* (x3,y3)是直线L上的点,从(x0,y0)画线到(x3,y3)。 只要我们取到直线L上面的所有显示的象素点,就可以实现三角形的填充。
*
* 问题:直线L有三种状态,竖直、水平和倾斜,竖直、水平状态,我们很容易解决。
* 倾斜状态,我们需要求得直线的斜率,这看似要使用浮点数,但是我们可以使用整数解决。
* 因为当直线(线段)上的两个端点point1,point2的横坐标x1!=x2时 即(x1-x2的绝对值大于等于1),
* 纵坐标的差值y2-y1最大是屏幕的高。所以(y1-y2)/(x1-x2)的值最大不超过屏幕的高度值。
* 这个值和Integer.Max_Value相差很多。这样我们可以把这个斜率放大1000倍之后使用。 这是可以斜率的精度的要求的。
*/
private void fillTriangle(Point point0, Point point1, Point point2) {
int x3, y3, state;
state = dealWithPoints(point0, point1, point2);
if (state == Line.Upright) {// 竖直
x3 = point1.x;
y3 = point1.y + 1;
do {
g.drawLine(point0.x, point0.y, x3, y3);
y3++;
} while (y3 < point2.y);
} else if (state == Line.Plane) {// 水平
x3 = point1.x;
y3 = point1.y;
do {
g.drawLine(point0.x, point0.y, x3, y3);
x3++;
} while (x3 < point2.x);
} else if (state == Line.Incline) {// 倾斜
int k = (point1.y - point2.y) * 1000 / (point1.x - point2.x);// 斜率,放大了1000倍
System.out.println("k is "+k);
y3 = point1.y + 1;
x3 = (y3 - point1.y) * 1000 / k + point1.x;
do {// 纵坐标++画一遍
g.drawLine(point0.x, point0.y, x3, y3);
y3++;
x3 = (y3 - point1.y) * 1000 / k + point1.x;
} while (y3 < point2.y);
if (point1.x > point2.x) {// 保证point1在左边
exchange(point1, point2);
}
y3 = point1.y + 1;
x3 = (y3 - point1.y) * 1000 / k + point1.x;
do {// 横坐标++画一遍
g.drawLine(point0.x, point0.y, x3, y3);
x3++;
y3 = (x3 - point1.x) * k / 1000 + point1.y;
} while (x3 < point2.x);
}
}
/**
* 处理三个点,得出哪个点做point0,哪个点做point1,哪个点做point2。
* 因为point0将做为画“射线族”的初始点,将另外的两个点命名为point1,point2 同时,调整两个点的reference。
* 这样处理的意义在于作图处理的时候的方便
*/
private int dealWithPoints(Point point0, Point point1, Point point2) {
if (point0.x == point1.x) {// 确定射线族顶点的对面的直线的状态,水平,竖直或倾斜,并对两个顶点的reference做出调整
exchange(point0, point2);
if (point1.y > point2.y) {// 保证point1在上边
exchange(point1, point2);
}
return Line.Upright;
} else if (point0.x == point2.x) {
exchange(point0, point1);
if (point1.y > point2.y) {// 保证point1在上边
exchange(point1, point2);
}
return Line.Upright;
} else if (point2.x == point1.x) {
if (point1.y > point2.y) {// 保证point1在上边
exchange(point1, point2);
}
return Line.Upright;
} else if (point0.y == point1.y) {
exchange(point0, point2);
if (point1.x > point2.x) {// 保证point1在左边
exchange(point1, point2);
}
return Line.Plane;
} else if (point0.y == point2.y) {
exchange(point0, point1);
if (point1.x > point2.x) {// 保证point1在左边
exchange(point1, point2);
}
return Line.Plane;
} else if (point2.y == point1.y) {
if (point1.x > point2.x) {// 保证point1在左边
exchange(point1, point2);
}
return Line.Plane;
} else {
if (point1.y > point2.y) {// 保证point1在上边
exchange(point1, point2);
}
return Line.Incline;
}
}
private void exchange(Point a, Point b) {// 交换两个点的reference
int tmp;
tmp = a.x;
a.x = b.x;
b.x = tmp;
tmp = a.y;
a.y = b.y;
b.y = tmp;
}
class Line {// 定义直线的三种状态,水平,竖直,倾斜
public static final int Plane = 0; // 水平
public static final int Upright = 1;// 竖直
public static final int Incline = 2;// 倾斜
}
class Point {// 定义点,包含横纵坐标
private int x, y;
public Point() {
this(0, 0);
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
}
代码的时间测试和稳定性测试都通过了。
但是还是有一些缺陷,比如
没有三个点是否可以组成三角形的检测。
在三角形区域较大的时候,运行的时间需要多一些,但是也不超过0.06秒,可以忍受。
另外,如果填充不是很完全,可以将三个点的先后位置调整一下,就可以了。比如
fillTriangle(point1, point0, point2);
如果你觉得不保险,可以“直接填充两次”:
fillTriangle(point0, point1, point2);
fillTriangle(point1, point0, point2);
嗯,就这么个思路,有问题可以联系我