MIDP1.0中实现三角形的填充

    在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);

嗯,就这么个思路,有问题可以联系我

MSN:cuilichen@hotmail.com


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值