绘图板程序设计及其具体实现 第二篇

工具包详细解析

( 一) 绘图处理工具类

Vector2f类

Vector2f类是一个表示二维向量的类,可以表示平面中的一个点或者一个向量。包含3个字段,x,y,w,w表示这个实例是一个点还是一个向量。对于点来说w=1,表示平移有效,可以用来变换矩阵;对于向量来说w=0,表示平移无效,不可以用来变换矩阵。

Vector2f类还包含一个静态字段EPSILON,表示可以区分Vector2f的最小值。因为浮点数的存储是不连续的,所以当两个Vector2f的距离小于EPSILON时就可以判断两个Vector2f是相等的。

  • Vector2f类方法一览表
修饰符返回值函数名参数说明
publicVector2f()默认构造函数,默认值为(0.0f, 0.0f, 1.0f)
publicVector2f(Vector2f v)构造函数
publicVector2f(float x, float y)构造函数,默认w=1
publicVector2f(float x, float y, float w)构造函数
publicvoidtranslate(float tx, float ty)平移
publicvoidscale(float s)x,y同比例缩放
publicvoidscale(float sx, float sy)x,y不同比例缩放
publicvoidrotate(float rad)旋转
publicvoidshear(float s)x,y同比例切变
publicvoidshear(float sx, float sy)x,y不同比例切变
publicVector2finv()返回相反的向量(-x,-y)
publicVector2fadd(Vector2f v)返回两个向量相加
publicVector2fsub(Vector2f v)返回两个向量相减
publicVector2fmul(float scalar)返回向量和实数相乘
publicVector2fdiv(float scalar)返回向量和实数相除
publicfloatlen()返回向量的长度
publicfloatlenSqr()返回向量长度的平方
publicVector2fnorm()返回向量的标准化向量
publicVector2fperp()返回向量的垂直向量(-y,x)
publicfloatdot(Vector2f v)返回两个向量点乘
publicfloatangle()返回向量与x轴正半轴的夹角,Pi~-Pi
public staticVector2fpolar(float angle, float radius)由向量的角度和长度构造向量
publicStringtoString()打印向量
publicbooleanequals(Object obj)比较两个向量是否相等
public finalbooleansimilar(Vector2f v, float EPSILON)判断两个向量是否在EPSILON程度上相似,即两向量之间的距离小于EPSILON
  • Vector2f类源代码
package Rendering.utils;

/**
 * This class is similar to Two-dimensional vector and 
 * has some operating functions.
 */
public class Vector2f {
    public static final float EPSILON = 0.00001f;

    public final boolean similar(Vector2f v, float EPSILON) {
        return this.sub(v).len() < EPSILON;
    }

    /**
     * The first dimension of the vector.
     */
    public float x;

    /**
     * The second dimension of the vector.
     */
    public float y;

    /**
     * The flag of the vector.
     * As for a point, the w should be 1;
     * But as a vector, the w should be 0;
     * Only when the w is 1 that the vector can translate a Matrix.
     */
    public float w;

    /**
     * Constructs a zero vector.
     */
    public Vector2f() {
        this.x = 0.0f;
        this.y = 0.0f;
        this.w = 1.0f;
    }

    /**
     * Constructs a vector copying from another vector.
     * @param v The vector to copy.
     */
    public Vector2f(Vector2f v) {
        this.x = v.x;
        this.y = v.y;
        this.w = v.w;
    }

    /**
     * Constructs a vector from two dimension.
     * @param x The first dimension of the vector.
     * @param y The second dimension of the vector.
     */
    public Vector2f(float x, float y) {
        this.x = x;
        this.y = y;
        this.w = 1.0f;
    }

    /**
     * Constructs a vector from two dimension
     * @param x The first dimension of the vector.
     * @param y The second dimension of the vector.
     * @param w The flag of the vector.
     */
    public Vector2f(float x, float y, float w) {
        this.x = x;
        this.y = y;
        this.w = w;
    }

    /**
     * Translate the vector.
     * @param tx The first dimension need to translate.
     * @param ty The second dimension need to translate.
     */
    public void translate(float tx, float ty) {
        x += tx;
        y += ty;
    }

    /**
     * Scale the vector.
     * @param s The multiple that need to scale.
     */
    public void scale(float s) {
        x *= s;
        y *= s;
    }

    /**
     * Scale the vector.
     * @param sx The multiple that need to scale in the first dimension.
     * @param sy The multiple that need to scale in the second dimension.
     */
    public void scale(float sx, float sy) {
        x *= sx;
        y *= sy;
    }

    /**
     * Rotate the vector.
     * @param rad The radian that need to rotate. 
     * And an angle should call the function Math.toRadians() 
     * to become a radian.
     */
    public void rotate(float rad) {
        float tmp = (float) (x * Math.cos(rad) - y * Math.sin(rad));
        y = (float) (x * Math.sin(rad) + y * Math.cos(rad));
        x=tmp;
    }

    /**
     * Shear the vector.
     * @param s The parameter the need to shear.
     */
    public void shear(float s) {
        float tmp = x + s * y;
        y = y + s * x;
        x = tmp;
    }

    /**
     * Shear the vector.
     * @param sx The parameter the need to shear in the first dimension.
     * @param sy The parameter the need to shear in the second dimension.
     */
    public void shear(float sx, float sy) {
        float tmp = x + sx * y;
        y = y + sy * x;
        x=tmp;
    }

    /**
     * Change the vector to the opposite one.
     * @return The opposite vector.
     */
    public Vector2f inv() {
        return new Vector2f(-x, -y);
    }

    /**
     * Add two vectors together.
     * @param v The add vector.
     * @return The result vector after adding the two vectors together.
     */
    public Vector2f add(Vector2f v) {
        return new Vector2f(x + v.x, y + v.y);
    }

    /**
     * Subtract two vectors.
     * @param v The subtract vector.
     * @return The result vector after subtracting the two vectors.
     */
    public Vector2f sub(Vector2f v) {
        return new Vector2f(x - v.x, y - v.y);
    }

    /**
     * Multiply the vector with a float number.
     * @param scalar The multiply float number.
     * @return The result vector after multiplying the vector 
     * with a float number.
     */
    public Vector2f mul(float scalar) {
        return new Vector2f(scalar * x, scalar * y);
    }

    /**
     * Divide the vector with a float number.
     * @param scalar The divide float number.
     * @return The result vector after dividing the vector 
     * with a float number.
     */
    public Vector2f div(float scalar) {
        return new Vector2f(x / scalar, y / scalar);
    }

    /**
     * Calculate the square of length of the vector.
     * @return The square of length of the vector.
     */
    public float len() {
        return (float) Math.sqrt(x * x + y * y);
    }

    /**
     * Calculate the length of the vector.
     * @return The length of the vector.
     */
    public float lenSqr() {
        return x * x + y * y;
    }

    /**
     * Normalizing the vector.
     * @return The normalization of the vector.
     */
    public Vector2f norm() {
        return div(len());
    }

    /**
     * Calculate the vertical vector of the vector.
     * @return A vertical vector of the vector.
     */
    public Vector2f perp() {
        return new Vector2f(-y, x);
    }

    /**
     * Dot multiply two vectors.
     * @param v The multiply vector.
     * @return The result vector after dot multiplying the two vectors.
     */
    public float dot(Vector2f v) {
        return x * v.x + y * v.y;
    }

    /**
     * Calculate the radian of the vector with the axis.
     * @return The radian of the vector with the axis. 
     * Ranging from Pi to -Pi.
     */
    public float angle() {
        return (float) Math.atan2(y, x);
    }

    /**
     * Create a vector with the radian and the length in 
     * the Polar coordinate system.
     * @param angle The radian of the vector.
     * @param radius The length of the vector.
     * @return The vector that has this radian and length.
     */
    public static Vector2f polar(float angle, float radius) {
        return new Vector2f(
                radius * (float) (Math.cos(angle)),
                radius * (float) (Math.sin(angle))
        );
    }

    @Override
    public String toString() {
        return String.format("(%s,%s)", x, y);
    }

    @Override
    public boolean equals(Object obj) {
        return this.similar((Vector2f) obj, EPSILON);
    }
}

Matrix3x3f类

Matrix3x3f类是一个表示三维矩阵的类,包含矩阵之间的基本运算以及矩阵与向量的运算。包含一个存储矩阵的3×3数组字段和一个表示维度的静态字段。

在平面的图形绘制过程中,Vector2f类可以表示平面中的一个点,利用Matrix3x3f类可以对Vector2f类执行变换操作,例如,平移,缩放,旋转,切变。可以由一个向量构造一个可以执行变换操作的变换矩阵,乘以需要执行变换操作的点即得到变换之后的点。若需要连续变换多次,可以先将变换矩阵相乘,再乘以需要执行变换操作的点,但是要注意矩阵相乘的顺序决定着变换的顺序。这两个类是平面图形绘制中非常重要的两个类。

  • Matrix3x3f类方法一览表
    |修饰符|返回值|函数名|参数|说明|
    |—|---|—|---|—|
    |public||Matrix3x3f|()|空构造函数|
    |public||Matrix3x3f|(float[][] m)|构造函数|
    |public|Matrix3x3f|add|(Matrix3x3f m1)|返回两个矩阵相加|
    |public|Matrix3x3f|sub|(Matrix3x3f m1)|返回两个矩阵相减|
    |public|Matrix3x3f|mul|(Matrix3x3f m1)|返回两个矩阵相乘|
    |public|void|setMatrix|(float[][] m)|设置矩阵的值|
    |public static|Matrix3x3f|zero|()|返回一个全零矩阵|
    |public static|Matrix3x3f|identity|()|返回一个单位矩阵|
    |public static|Matrix3x3f|translate|(Vector2f v)|返回一个执行平移操作的矩阵|
    |public static|Matrix3x3f|translate|(float x,float y)|返回一个执行平移操作的矩阵|
    |public static|Matrix3x3f|scale|(Vector2f v)|返回一个执行缩放操作的矩阵|
    |public static|Matrix3x3f|scale|(float x,float y)|返回一个执行缩放操作的矩阵|
    |public static|Matrix3x3f|shear|(Vector2f v)|返回一个执行切变操作的矩阵|
    |public static|Matrix3x3f|shear|(float x,float y)|返回一个执行切变操作的矩阵|
    |public static|Matrix3x3f|rotate|(float rad)|返回一个执行旋转操作的矩阵|
    |public|Vector2f|mul|(Vector2f vec)|对需要执行变换的点执行变换操作|
    |public|String|toString|()|打印矩阵|

  • Matrix3x3f类源代码

package Rendering.utils;

/**
 * This class is similar to Tri-dimensional matrix and 
 * has some operating functions.
 */
public class Matrix3x3f {
    public static final int DIMENSION = 3;
    private float[][] m = new float[DIMENSION][DIMENSION];

    public Matrix3x3f() {}

    public Matrix3x3f(float[][] m) {
        setMatrix(m);
    }

    public Matrix3x3f add(Matrix3x3f m1) {
        float[][] tmp = new float[DIMENSION][DIMENSION];
        for (int i = 0; i < DIMENSION; i++) {
            for (int j = 0; j < DIMENSION; j++) {
                tmp[i][j] = m[i][j] + m1.m[i][j];
            }
        }
        return new Matrix3x3f(tmp);
    }

    public Matrix3x3f sub(Matrix3x3f m1) {
        float[][] tmp = new float[DIMENSION][DIMENSION];
        for (int i = 0; i < DIMENSION; i++) {
            for (int j = 0; j < DIMENSION; j++) {
                tmp[i][j] = m[i][j] - m1.m[i][j];
            }
        }
        return new Matrix3x3f(tmp);
    }

    public Matrix3x3f mul(Matrix3x3f m1) {
        float[][] tmp = new float[DIMENSION][DIMENSION];
        for (int i = 0; i < DIMENSION; i++) {
            for (int k = 0; k < DIMENSION; k++) {
                for(int j=0;j<DIMENSION;j++) {
                    tmp[i][j] += m[i][k] * m1.m[k][j];
                }
            }
        }
        return new Matrix3x3f(tmp);
    }

    public void setMatrix(float[][] m) {
        if (m.length == DIMENSION && m[0].length == DIMENSION) {
            this.m = m;
        }
    }

    public static Matrix3x3f zero() {
        return new Matrix3x3f(new float[DIMENSION][DIMENSION]);
    }

    public static Matrix3x3f identity() {
        float[][] tmp = new float[DIMENSION][DIMENSION];
        for (int i = 0; i < DIMENSION; i++) {
            tmp[i][i] = 1.0f;
        }
        return new Matrix3x3f(tmp);
    }

    public static Matrix3x3f translate(Vector2f v) {
        return translate(v.x, v.y);
    }

    public static Matrix3x3f translate(float x, float y) {
        return new Matrix3x3f(new float[][]{
                {1.0f, 0.0f, 0.0f},
                {0.0f, 1.0f, 0.0f},
                {x, y, 1.0f}
        });
    }

    public static Matrix3x3f scale(Vector2f v) {
        return scale(v.x, v.y);
    }

    public static Matrix3x3f scale(float x, float y) {
        return new Matrix3x3f(new float[][]{
                {x, 0.0f, 0.0f},
                {0.0f, y, 0.0f},
                {0.0f, 0.0f, 1.0f}
        });
    }

    public static Matrix3x3f shear(Vector2f v) {
        return shear(v.x, v.y);
    }

    public static Matrix3x3f shear(float x, float y) {
        return new Matrix3x3f(new float[][]{
                {1.0f, y, 0.0f},
                {x, 1.0f, 0.0f},
                {0.0f, 0.0f, 1.0f}
        });
    }

    public static Matrix3x3f rotate(float rad) {
        return new Matrix3x3f(new float[][]{
                {(float) Math.cos(rad), (float) Math.sin(rad), 0.0f},
                {(float) -Math.sin(rad), (float) Math.cos(rad), 0.0f},
                {0.0f, 0.0f, 1.0f}
        });
    }

    public Vector2f mul(Vector2f vec) {
        return new Vector2f(
                vec.x * this.m[0][0]
                        + vec.y * this.m[1][0]
                        + vec.w * this.m[2][0],
                vec.x * this.m[0][1]
                        + vec.y * this.m[1][1]
                        + vec.w * this.m[2][1],
                vec.x * this.m[0][2]
                        + vec.y * this.m[1][2]
                        + vec.w * this.m[2][2]
        );
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        for(int i=0;i<DIMENSION;i++) {
            buf.append("[");
            buf.append(m[i][0]);
            buf.append(",\t");
            buf.append(m[i][1]);
            buf.append(",\t");
            buf.append(m[i][2]);
            buf.append("]\n");
        }
        return buf.toString();
    }
}

Utility类

Utility类是所有的工具函数的集合类,其中包括坐标转换工具,图形绘制工具,文字绘制工具。Utility类可以引用到任何使用Graphics进行图形绘制的程序中,其中的点,坐标变换分别用Vector2f和Matrix3x3f来表示。

  • Utility类方法一览表
修饰符返回值函数名参数说明
public staticMatrix3x3fcreateViewport(float worldWidth,float worldHeight,float screenWidth,float screenHeight)返回由世界坐标转换到屏幕坐标的转换矩阵
public staticMatrix3x3fcreateReverseViewport(float worldWidth,float worldHeight,float screenWidth,float screenHeight)返回由屏幕坐标转换到世界坐标的转换矩阵
public staticVector2f[]transform(Vector2f[] poly,Matrix3x3f mat)对一系列的点进行指定的转换
public staticvoiddrawPolygon(Graphics2D g2d,Vector2f[] polygon,Matrix3x3f view,Color color)根据点的个数绘制多边形,点,或直线
public staticvoiddrawPolygon(Graphics2D g2d,List< Vector2f> polygon,Matrix3x3f view,Color color)根据点的个数绘制多边形,点,或直线
public staticvoidfillPolygon(Graphics2D g2d,Vector2f[] polygon,Matrix3x3f view,Color color)根据点的个数绘制填充多边形,点,或直线
public staticvoidfillPolygon(Graphics2D g2d,List< Vector2f> polygon,Matrix3x3f view,Color color)根据点的个数填充绘制多边形,点,或直线
public staticvoiddrawRect(Graphics2D g2d,Vector2f topLeft,Vector2f bottomRight,Matrix3x3f view,Color color)由矩形的两个角的位置绘制矩形
public staticvoidfillRect(Graphics2D g2d,Vector2f topLeft,Vector2f bottomRight,Matrix3x3f view,Color color)由矩形的两个角的位置绘制填充矩形
public staticvoiddrawCircle(Graphics2D g2d,Vector2f center,float radius,Matrix3x3f view,Color color)由圆心的位置和半径绘制圆
public staticvoidfillCircle(Graphics2D g2d,Vector2f center,float radius,Matrix3x3f view,Color color)由圆心的位置和半径绘制填充圆
public staticvoiddrawCircle(Graphics2D g2d,Vector2f begin,Vector2f end,Matrix3x3f view,Color color)由圆心和圆上一点的位置绘制圆
public staticvoidfillCircle(Graphics2D g2d,Vector2f begin,Vector2f end,Matrix3x3f view,Color color)由圆心和圆上一点的位置绘制填充圆
public staticvoiddrawOval(Graphics2D g2d,Vector2f topLeft,Vector2f bottomRight,Matrix3x3f view,Color color)由椭圆的外切矩形的两个角的位置绘制椭圆
public staticvoidfillOval(Graphics2D g2d,Vector2f topLeft,Vector2f bottomRight,Matrix3x3f view,Color color)由椭圆的外切矩形的两个角的位置绘制填充椭圆
public staticvoiddrawTriangle(Graphics2D g2d,Vector2f begin,Vector2f center,Matrix3x3f view,Color color)由三角形的一个角和中心的位置绘制等边三角形
public staticvoidfillTriangle(Graphics2D g2d,Vector2f begin,Vector2f center,Matrix3x3f view,Color color)由三角形的一个角和中心的位置绘制填充等边三角形
public staticvoidfillSimilarCircle(Graphics2D g2d,Vector2f position,Matrix3x3f view)由圆心的位置绘制指定的快捷选择操作圆(快捷选择操作中用到)
public staticvoiddrawString(Graphics2D g2d,Vector2f position,Matrix3x3f view,Color color,String… str)在指定位置绘制字符串
public staticvoiddrawString(Graphics2D g2d,Vector2f position,Matrix3x3f view,Color color,List< String> str)在指定位置绘制字符串
public staticvoiddrawString(Graphics2D g2d,Vector2f position,Matrix3x3f view,Color color,String str)在指定位置绘制字符串
  • Utility类源代码
package Rendering.utils;

import Rendering.element.BeginEndImageElement;

import java.awt.*;
import java.util.List;

public class Utility {
    /****************************************************************************/
    /*********************Coordinate transformation tool*************************/
    /****************************************************************************/
    public static Matrix3x3f createViewport(
            float worldWidth, float worldHeight,
            float screenWidth, float screenHeight) {
        float sx = (screenWidth - 1) / worldWidth;
        float sy = (screenHeight - 1) / worldHeight;
        float tx = (screenWidth - 1) / 2.0f;
        float ty = (screenHeight - 1) / 2.0f;
        Matrix3x3f viewport = Matrix3x3f.scale(sx, -sy);
        viewport = viewport.mul(Matrix3x3f.translate(tx, ty));
        return viewport;
    }

    public static Matrix3x3f createReverseViewport(
            float worldWidth, float worldHeight,
            float screenWidth, float screenHeight) {
        float sx = worldWidth / (screenWidth - 1);
        float sy = worldHeight / (screenHeight - 1);
        float tx = (screenWidth - 1) / 2.0f;
        float ty = (screenHeight - 1) / 2.0f;
        Matrix3x3f viewport = Matrix3x3f.translate(-tx, -ty);
        viewport = viewport.mul(Matrix3x3f.scale(sx, -sy));
        return viewport;
    }

    public static Vector2f[] transform(Vector2f[] poly, Matrix3x3f mat) {
        Vector2f[] copy = new Vector2f[poly.length];
        for (int i = 0; i < poly.length; i++) {
            copy[i] = mat.mul(poly[i]);
        }
        return copy;
    }

    /****************************************************************************/
    /*********************Graphic drawing tool***********************************/
    /****************************************************************************/
    public static void drawPolygon(
            Graphics2D g2d, Vector2f[] polygon,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f[] tmp = transform(polygon, view);
        if (tmp.length == 1) {
            g2d.drawRect((int) tmp[0].x, (int) tmp[0].y, 1, 1);
        }
        Vector2f P;
        Vector2f S = tmp[tmp.length - 1];
        for (int i = 0; i < tmp.length; i++) {
            P = tmp[i];
            g2d.drawLine((int) S.x, (int) S.y, (int) P.x, (int) P.y);
            S = P;
        }
    }

    public static void drawPolygon(
            Graphics2D g2d, List<Vector2f> polygon,
            Matrix3x3f view, Color color) {
        drawPolygon(g2d, polygon.toArray(new Vector2f[0]), view, color);
    }

    public static void fillPolygon(
            Graphics2D g2d, Vector2f[] polygon,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f[] tmp = transform(polygon, view);
        Polygon p = new Polygon();
        for (Vector2f v : tmp) {
            p.addPoint((int) v.x, (int) v.y);
        }
        g2d.fillPolygon(p);
    }

    public static void fillPolygon(
            Graphics2D g2d, List<Vector2f> polygon,
            Matrix3x3f view, Color color) {
        fillPolygon(g2d, polygon.toArray(new Vector2f[0]), view, color);
    }

    public static void drawRect(
            Graphics2D g2d, Vector2f topLeft, Vector2f bottomRight,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f topLeftTmp = view.mul(topLeft);
        Vector2f bottomRightTmp = view.mul(bottomRight);
        if (bottomRight.y > topLeft.y) {
            float tmp = topLeftTmp.y;
            topLeftTmp.y = bottomRightTmp.y;
            bottomRightTmp.y = tmp;
        }
        if (bottomRight.x < topLeft.x) {
            float tmp = topLeftTmp.x;
            topLeftTmp.x = bottomRightTmp.x;
            bottomRightTmp.x = tmp;
        }
        int rectX = (int) topLeftTmp.x;
        int rectY = (int) topLeftTmp.y;
        int rectWidth = (int) (bottomRightTmp.x - topLeftTmp.x);
        int rectHeight = (int) (bottomRightTmp.y - topLeftTmp.y);
        g2d.drawRect(rectX, rectY, rectWidth, rectHeight);
    }

    public static void fillRect(
            Graphics2D g2d, Vector2f topLeft, Vector2f bottomRight,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f topLeftTmp = view.mul(topLeft);
        Vector2f bottomRightTmp = view.mul(bottomRight);
        if (bottomRight.y > topLeft.y) {
            float tmp = topLeftTmp.y;
            topLeftTmp.y = bottomRightTmp.y;
            bottomRightTmp.y = tmp;
        }
        if (bottomRight.x < topLeft.x) {
            float tmp = topLeftTmp.x;
            topLeftTmp.x = bottomRightTmp.x;
            bottomRightTmp.x = tmp;
        }
        int rectX = (int) topLeftTmp.x;
        int rectY = (int) topLeftTmp.y;
        int rectWidth = (int) (bottomRightTmp.x - topLeftTmp.x);
        int rectHeight = (int) (bottomRightTmp.y - topLeftTmp.y);
        g2d.fillRect(rectX, rectY, rectWidth, rectHeight);
    }

    public static void drawCircle(
            Graphics2D g2d, Vector2f center, float radius,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f topLeft =
                new Vector2f(center.x - radius, center.y + radius);
        topLeft = view.mul(topLeft);
        Vector2f bottomRight =
                new Vector2f(center.x + radius, center.y - radius);
        bottomRight = view.mul(bottomRight);
        Vector2f centerTmp = view.mul(center);
        int circleX = (int) topLeft.x;
        int circleY = (int) topLeft.y;
        int circleWidth = (int) (bottomRight.x - topLeft.x);
        int circleHeight = (int) (bottomRight.y - topLeft.y);
        g2d.drawRect((int) centerTmp.x, (int) centerTmp.y, 1, 1);
        g2d.drawOval(circleX, circleY, circleWidth, circleHeight);
    }

    public static void fillCircle(
            Graphics2D g2d, Vector2f center, float radius,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f topLeft =
                new Vector2f(center.x - radius, center.y + radius);
        topLeft = view.mul(topLeft);
        Vector2f bottomRight =
                new Vector2f(center.x + radius, center.y - radius);
        bottomRight = view.mul(bottomRight);
        int circleX = (int) topLeft.x;
        int circleY = (int) topLeft.y;
        int circleWidth = (int) (bottomRight.x - topLeft.x);
        int circleHeight = (int) (bottomRight.y - topLeft.y);
        g2d.fillOval(circleX, circleY, circleWidth, circleHeight);
    }

    public static void drawCircle(
            Graphics2D g2d, Vector2f begin, Vector2f end,
            Matrix3x3f view, Color color) {
        drawCircle(g2d, begin, begin.sub(end).len(), view, color);
    }

    public static void fillCircle(
            Graphics2D g2d, Vector2f begin, Vector2f end,
            Matrix3x3f view, Color color) {
        fillCircle(g2d, begin, begin.sub(end).len(), view, color);
    }

    public static void drawOval(
            Graphics2D g2d, Vector2f topLeft, Vector2f bottomRight,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f topLeftTmp = view.mul(topLeft);
        Vector2f bottomRightTmp = view.mul(bottomRight);
        if (bottomRight.y > topLeft.y) {
            float tmp = topLeftTmp.y;
            topLeftTmp.y = bottomRightTmp.y;
            bottomRightTmp.y = tmp;
        }
        if (bottomRight.x < topLeft.x) {
            float tmp = topLeftTmp.x;
            topLeftTmp.x = bottomRightTmp.x;
            bottomRightTmp.x = tmp;
        }
        int ovalX = (int) topLeftTmp.x;
        int ovalY = (int) topLeftTmp.y;
        int ovalWidth = (int) (bottomRightTmp.x - topLeftTmp.x);
        int ovalHeight = (int) (bottomRightTmp.y - topLeftTmp.y);
        g2d.drawOval(ovalX, ovalY, ovalWidth, ovalHeight);
    }

    public static void fillOval(
            Graphics2D g2d, Vector2f topLeft, Vector2f bottomRight,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f topLeftTmp = view.mul(topLeft);
        Vector2f bottomRightTmp = view.mul(bottomRight);
        if (bottomRight.y > topLeft.y) {
            float tmp = topLeftTmp.y;
            topLeftTmp.y = bottomRightTmp.y;
            bottomRightTmp.y = tmp;
        }
        if (bottomRight.x < topLeft.x) {
            float tmp = topLeftTmp.x;
            topLeftTmp.x = bottomRightTmp.x;
            bottomRightTmp.x = tmp;
        }
        int ovalX = (int) topLeftTmp.x;
        int ovalY = (int) topLeftTmp.y;
        int ovalWidth = (int) (bottomRightTmp.x - topLeftTmp.x);
        int ovalHeight = (int) (bottomRightTmp.y - topLeftTmp.y);
        g2d.fillOval(ovalX, ovalY, ovalWidth, ovalHeight);
    }

    public static void drawTriangle(
            Graphics2D g2d, Vector2f begin, Vector2f center,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f tmp = center.sub(begin);
        Vector2f topTmp = begin.add(
                Vector2f.polar(
                        new Double(tmp.angle() + Math.PI / 6.0).floatValue(),
                        new Double(tmp.len() * Math.sqrt(3.0)).floatValue()));
        Vector2f bottomTmp = begin.add(
                Vector2f.polar(
                        new Double(tmp.angle() - Math.PI / 6.0).floatValue(),
                        new Double(tmp.len() * Math.sqrt(3.0)).floatValue()));
        drawPolygon(g2d, new Vector2f[]{begin, topTmp, bottomTmp}, view, color);
    }

    public static void fillTriangle(
            Graphics2D g2d, Vector2f begin, Vector2f center,
            Matrix3x3f view, Color color) {
        g2d.setColor(color);
        Vector2f tmp = center.sub(begin);
        Vector2f topTmp = begin.add(
                Vector2f.polar(
                        new Double(tmp.angle() + Math.PI / 6.0).floatValue(),
                        new Double(tmp.len() * Math.sqrt(3.0)).floatValue()));
        Vector2f bottomTmp = begin.add(
                Vector2f.polar(
                        new Double(tmp.angle() - Math.PI / 6.0).floatValue(),
                        new Double(tmp.len() * Math.sqrt(3.0)).floatValue()));
        fillPolygon(g2d, new Vector2f[]{begin, topTmp, bottomTmp}, view, color);
    }

    public static void fillSimilarCircle(
            Graphics2D g2d, Vector2f position, Matrix3x3f view) {
        fillCircle(g2d, position, BeginEndImageElement.EPSILON, view, Color.YELLOW);
        Vector2f r = Vector2f.polar((float) (Math.PI / 4), BeginEndImageElement.EPSILON);
        Vector2f rightTop = position.add(r);
        Vector2f leftBottom = position.sub(r);
        Vector2f rightBottom = position.add(r.perp());
        Vector2f leftTop = position.sub(r.perp());
        drawPolygon(g2d, new Vector2f[]{rightTop, leftBottom}, view, Color.BLACK);
        drawPolygon(g2d, new Vector2f[]{leftTop, rightBottom}, view, Color.BLACK);
    }

    /****************************************************************************/
    /************************String drawing tool*********************************/
    /****************************************************************************/
    public static void drawString(
            Graphics2D g2d, Vector2f position,
            Matrix3x3f view, Color color, 
            String... str) {
        g2d.setColor(color);
        Vector2f positionTmp = view.mul(position);
        float x = positionTmp.x;
        float y = positionTmp.y;
        FontMetrics fm = g2d.getFontMetrics();
        int height = fm.getAscent() + fm.getDescent() + fm.getLeading();
        g2d.setFont(new Font("Courier New", Font.PLAIN, 20));
        g2d.setRenderingHint(
                RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        for (String s : str) {
            g2d.drawString(s, x, y + fm.getAscent());
            y += height;
        }
    }

    public static void drawString(
            Graphics2D g2d, Vector2f position,
            Matrix3x3f view, Color color, 
            List<String> str) {
        drawString(g2d, position, view, color, str.toArray(new String[0]));
    }

    public static void drawString(
            Graphics2D g2d, Vector2f position,
            Matrix3x3f view, Color color, 
            String str) {
        drawString(g2d, position, view, color, new String[]{str});
    }
}

更多:

第一篇
第二篇
第三篇
第四篇
第五篇
第六篇
第七篇
最终篇
源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值