绘制函数图象小工具

作者在 2012-09-16 00:41:14 发布以下内容
介绍:

       这是一款绘制函数图象轻量级小程序,希望他可以给大家对于简单绘图带来很大的便捷;目前版本支持各类简单函数,及复合函数图象的绘制,且在细节上比较符合我们平时绘图的习惯,提供函数图象的导出保存功能,理论上可以同时在一张面板上绘制的图象数量是不受限制的,但还是建议不要超过30个。今天是个特殊的日子,也希望我的小程序可以带给大家一些快乐。

部分源码:package FunctionImage_1;


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JPanel;
import javax.xml.transform.Templates;

public class MyPanelCenter extends JPanel {
    Point oPoint = null; // 坐标原点
    FPoint resultPoint[] = null; // 函数图象点集
    int space = 10;// 坐标系周围间距
    int sl = 5;// 标准最小刻度像素点大小
    int snl = 5;// 标准坐标上数字间间距刻度大小,1个数学单位之间有snl个刻度
    double nSize = 1;// 每个坐标数学单位对应实际函数中的数学单位
    double pointsize = 1000;// 要计算点的个数
    double xstart, xend;// 函数现行定义域
    int flag = 0;// 特殊缩小标记
    double rangeXstart, rangeXend;// 初始定义域
    int lineSizeFlag = 1;// 默认线条为细
    ReadExPre readExPre;// 解读表达式的类
    ArrayList<FunctionExpression> expressionsList;// 存放函数表达式的顺序表

    public MyPanelCenter() {
        super();
        readExPre = new ReadExPre();
        expressionsList = new ArrayList<>();
    }

    public void changeBiger() {// 把坐标系变大
        if (flag == 1) {
            nSize *= 2;
            if (nSize == 1) {
                flag = 0;
            }
        } else {
            sl += 5;
        }
    }

    public void changeLittler() {// 把坐标系变小,实际表示范围扩大
        if (sl > 5) {// 未达到最小刻度
            sl -= 5;
        } else {// 达到最小刻度
            flag = 1;
            nSize /= 2;
        }
    }

    public void clear(Graphics g) {
        // 覆盖原来的
        g.setColor(Color.white);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
    }

    public void paint(Graphics g) {
        // 覆盖原来的
        clear(g);
        // 画坐标系
        paintTheXoY(g);
        // 绘制函数列表里的函数图象
        paintAllFun(g);
        // 绘制函数标识
        paintTheFunFlag(g);
    }

    public void paintTheXoY(Graphics g) {// 画坐标系
        if (oPoint == null) {
            oPoint = new Point(this.getWidth() / 2, this.getHeight() / 2);
        }
        // 画坐标轴
        g.setColor(Color.GREEN);
        g.drawLine(oPoint.x, space, oPoint.x, this.getHeight() - 2 * space);
        g.drawLine(space, oPoint.y, this.getWidth() - 2 * space, oPoint.y);
        g.drawString("y", oPoint.x, space - 2);
        g.drawString("x", this.getWidth() - space, oPoint.y);
        // y箭头
        g.drawLine(oPoint.x, space, oPoint.x - 5, space + 5);
        g.drawLine(oPoint.x, space, oPoint.x + 5, space + 5);
        // x箭头
        g.drawLine(this.getWidth() - 2 * space - 5, oPoint.y + 5,
                this.getWidth() - 2 * space, oPoint.y);
        g.drawLine(this.getWidth() - 2 * space - 5, oPoint.y - 5,
                this.getWidth() - 2 * space, oPoint.y);
        // 画坐标
        
// x
        int xlength = oPoint.x;
        // 左侧
        for (int temp = sl; temp + space < oPoint.x; temp += sl) {
            if (temp % (sl * snl) == 0) {
                g.drawString("-" + temp / (sl * snl * nSize) + "", xlength
                        - temp - 5, oPoint.y + 15);
                g.drawLine(xlength - temp, oPoint.y + 3, xlength - temp,
                        oPoint.y - 3);
                // rangeXstart = -temp / (sl * snl * nSize);
            } else {
                g.drawLine(xlength - temp, oPoint.y + 1, xlength - temp,
                        oPoint.y - 1);
            }
        }
        rangeXstart = -(oPoint.x - space) / (sl * snl * nSize);
        if (oPoint.x < 0) {// 原点移至panel左侧外
            rangeXstart = (0 + space - oPoint.x) / (sl * snl * nSize);// 取左侧作为当前定义域上端
        }
        // 右侧
        for (int temp = sl; temp + space < this.getWidth() - oPoint.x - sl; temp += sl) {
            if (temp % (sl * snl) == 0) {
                g.drawString(temp / (sl * snl * nSize) + "",
                        xlength + temp - 5, oPoint.y + 15);
                g.drawLine(xlength + temp, oPoint.y + 3, xlength + temp,
                        oPoint.y - 3);
                // rangeXend = temp / (sl * snl * nSize);
            } else {
                g.drawLine(xlength + temp, oPoint.y + 1, xlength + temp,
                        oPoint.y - 1);
            }
        }
        rangeXend = (this.getWidth() - space - oPoint.x) / (sl * snl * nSize);
        if (oPoint.x > this.getWidth()) {// 原点移至panel右侧外
            rangeXend = (oPoint.x - this.getWidth() - space)
                    / (sl * snl * nSize);// 取右侧目前坐标值作为当前定义域上端
        }
        // y
        int ylength = oPoint.y;
        // 上侧
        for (int temp = sl; temp + space < oPoint.y; temp += sl) {
            if (temp % (sl * snl) == 0) {
                g.drawString(temp / (sl * snl * nSize) + "", oPoint.x - 25,
                        ylength - temp + 5);
                g.drawLine(oPoint.x + 3, ylength - temp, oPoint.x - 3, ylength
                        - temp);
            } else {
                g.drawLine(oPoint.x + 1, ylength - temp, oPoint.x - 1, ylength
                        - temp);
            }
        }
        // 下侧
        for (int temp = sl; temp + space < this.getHeight() - oPoint.y - sl; temp += sl) {
            if (temp % (sl * snl) == 0) {
                g.drawString("-" + temp / (sl * snl * nSize) + "",
                        oPoint.x - 25, ylength + temp + 5);
                g.drawLine(oPoint.x + 3, ylength + temp, oPoint.x - 3, ylength
                        + temp);
            } else {
                g.drawLine(oPoint.x + 1, ylength + temp, oPoint.x - 1, ylength
                        + temp);
            }
        }
    }

    public void paintTheFunFlag(Graphics g) { // 画函数识别标记
        Iterator<FunctionExpression> iterator = expressionsList.iterator();
        int FstrLocationY = 10, FstrLocationX = 10;
        while (iterator.hasNext()) {
            FunctionExpression temFunctionExpression = iterator.next();
            if (FstrLocationY < this.getHeight() - 20) {
                g.setColor(temFunctionExpression.color);
                g.fillRect(FstrLocationX, FstrLocationY, 10, 2);
                g.drawString(temFunctionExpression.expression,
                        FstrLocationX + 13, FstrLocationY + 5);
                FstrLocationY += 10;
            }
        }
    }

    public void clearTheFunFlag(Graphics g) { // 覆盖掉之前的函数识别标记
        Iterator<FunctionExpression> iterator = expressionsList.iterator();
        int FstrLocationY = 10, FstrLocationX = 10;
        while (iterator.hasNext()) {
            FunctionExpression temFunctionExpression = iterator.next();
            if (FstrLocationY < this.getHeight() - 20) {
                g.setColor(Color.white);
                g.fillRect(FstrLocationX, FstrLocationY, 10, 2);
                g.drawString(temFunctionExpression.expression,
                        FstrLocationX + 13, FstrLocationY + 5);
                FstrLocationY += 10;
            }
        }
    }

    public void paintAllFun(Graphics g) {
        Iterator<FunctionExpression> iterator = expressionsList.iterator();
        while (iterator.hasNext()) {
            FunctionExpression temFunctionExpression = iterator.next();
            try {
                paintOneFun(g, temFunctionExpression.expression,
                        temFunctionExpression.color);
            } catch (IllegalExpressionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void paintOneFun(Graphics g, String expression, Color color)
            throws IllegalExpressionException {// 画一个函数的图像
        
// 计算点
        createFPoints(expression);
        // 描点连线
        paintFunction(g, color);
    }

    public void paintFunction(Graphics g, Color color) { // 描点连线
        FPoint temStart, temEnd;
        g.setColor(color);
        for (int i = 0; i < resultPoint.length - 1; i++) {
            temStart = resultPoint[i];
            // System.out.println("(" + temStart.x + " , " + temStart.y + ")");
            temEnd = resultPoint[i + 1];
            // System.out.println("(" + temStart.x + " , " + temStart.y + ")");
            if (temEnd != null && temStart != null&&temEnd.flag==1&&temStart.flag==1) {
                // if (pointInXoY(temEnd) || pointInXoY(temStart)) {
                
// if (lineSizeFlag == 1) {
                g.drawLine(temStart.x, temStart.y, temEnd.x, temEnd.y);
                // }
                if (lineSizeFlag == 2) {// 把线条加粗
                    
// g.drawLine(temStart.x - 1, temStart.y, temEnd.x,
                    
// temEnd.y);
                    
// g.drawLine(temStart.x, temStart.y, temEnd.x + 1,
                    
// temEnd.y);
                    g.drawLine(temStart.x, temStart.y + 1, temEnd.x,
                            temEnd.y + 1);
                    g.drawLine(temStart.x + 1, temStart.y, temEnd.x + 1,
                            temEnd.y);
                    // g.drawLine(temStart.x, temStart.y-1, temEnd.x,
                    
// temEnd.y-1);
                }
                // }
            }
        }
        resultPoint = null;// 内存留待回收
    }

    public boolean pointInXoY(Point p) {// 点是否在坐标系里
        if (p.x >= 0 && p.y >= 0 && p.x <= getWidth() && p.y <= getHeight()) {
            return true;
        }
        return false;
    }

    public void createFPoints(String expression)
            throws IllegalExpressionException { // 生成一组点集
        setRange(expression);// 纠正定义域
        double xRange = xend - xstart;// 域宽
        double oneStepL = xRange / pointsize;// 初始化步长
        resultPoint = new FPoint[(int) pointsize + 1];
        int index = 0;
        double temy;
        int temypie = Integer.MAX_VALUE;
        for (double i = xstart; i <= xend; i += oneStepL, index++) {
            temy = compute(i, expression);
                if (!Double.isNaN(temy)) {
                if (temy == Double.POSITIVE_INFINITY) {
                    resultPoint[index] = new FPoint(0,0,0);//加入一个无效点
                    index++;
                    temypie = Integer.MAX_VALUE;
                } else if (temy == Double.NEGATIVE_INFINITY) {
                    temypie = Integer.MIN_VALUE;
                } else {
                    temypie = (int) (temy * sl * snl * nSize);
                }
                resultPoint[index] = new FPoint((int) (i * sl * snl * nSize)
                        + oPoint.x, oPoint.y - temypie, 1);
            }
        }
    }

    public void setRange(String expression) {
        if (expression.equals("logx") || expression.equals("lgx")) {
            if (rangeXstart <= 0) {
                xstart = 1.3e-300;
            }
            xend = rangeXend;
        } else if (expression.equals("cosh(x)") || expression.equals("sinh(x)")) {
            xstart = -1;
            xend = 1;
        } else {
            xstart = rangeXstart;
            xend = rangeXend;
        }
    }

    public double compute(double x, String expression)
            throws IllegalExpressionException {// 计算函数值
        double y = Double.NaN;// 初始值为nan
        y = readExPre.readExpression(new StringBuffer(expression), x);
        // double y = Math.pow(x, 5) + 2 * x * x;
        
// double y=Math.tan(x);
        
// double y=Math.sin(x)/x;
        
// double y=-Math.sin(x)*x*x*9.8/2;
        
// System.out.println("(x" + x + " , y" + y + ")");
        
// System.out.println("(x" + (int)(x*sl*snl) + " , y" + (int)(y*sl*snl)
        
// + ")");
        return y;
    }

    public boolean moveToXY(double x, double y) {
        // 计算(x,y)的像素坐标
        double temx = x * sl * snl * nSize + oPoint.x, temy = oPoint.y - y * sl
                * snl * nSize;
        if (temx > Integer.MAX_VALUE || temy > Integer.MAX_VALUE
                || temx < Integer.MIN_VALUE || temy < Integer.MIN_VALUE) {
            return false;
        }
        int xpie = (int) (temx);
        int ypie = (int) (temy);
        // 移动原点
        oPoint.x -= xpie - getWidth() / 2;
        oPoint.y -= ypie - getHeight() / 2;
        repaint();
        return true;
    }

    public double getPointsize() {
        return pointsize;
    }

    public void setPointsize(double pointsize) {
        this.pointsize = pointsize;
    }

    public void addExp(String exp, Color color) {
        expressionsList.add(new FunctionExpression(exp, color));
    }

    public void removeExp(String exp) {
        Iterator<FunctionExpression> iterator = expressionsList.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().expression.equals(exp)) {
                iterator.remove();
            }
        }
    }

    public void paintOnePie(Graphics g, int x, int y) {
        g.setColor(Color.blue);
        g.drawOval(x - 5, y - 5, 10, 10);
        g.drawOval(x - 3, y - 3, 6, 6);
    }
}

class FunctionExpression {
    String expression;
    Color color;

    public FunctionExpression(String exp, Color color) {
        expression = exp;
        this.color = color;
    }
}

class FPoint {
    int x;
    int y;
    int flag = 1;// 有效点

    public FPoint(int x, int y, int flag) {
        this.x = x;
        this.y = y;
        this.flag = flag;
    }
}
  程序截图:
swt | 阅读 2414 次
文章评论,共5条
zxjidian
2014-08-06 08:52
1
朋友你好,大概看了你的这篇博客我找到了对我有帮助的东西,但是我还是有些地方不清楚,能麻烦你帮我一下吗?

我要实现的功能:假设我有几十万个坐标点,然后要显示在一个坐标系中并且要求是动态显示,这个坐标系会根据加入的点的大小自动调节X Y轴的刻度,并且能够实现对绘制的图像进行缩放。

我的QQ 306789402 希望你能帮我,谢谢!
维海(作者)
2014-08-08 16:29
2
这个你就实现下逻辑坐标系到物理坐标系的映射关系就好了,主要还是考虑效率问题,毕竟几十万个坐标点呢
维海(作者)
2014-08-08 16:37
3
这里有详细点的介绍http://www.oschina.net/code/snippet_585649_13831
这里是源码地址:http://pan.baidu.com/s/1kTyXIZH
z从头再来
2017-04-05 17:59
4
你好,我最近在学习这个函数绘图发面的东西,能提供完整的代码参考一下吗?万分感谢!(上面的百度网盘失效了)
米远式宋(游客)
2021-04-07 21:59
5
以下是引用z从头再来在2017-04-05 17:59的发言1
你好,我最近在学习这个函数绘图发面的东西,能提供完整的代码参考一下吗?万分感谢!(上面的百度网盘失效了)
不好意思,好久没看这个博客了,刚发现
链接: https://pan.baidu.com/s/1X5SVQwJYSlzj8K5XgXnllw 提取码: 4ug4 复制这段内容后打开百度网盘手机App,操作更方便哦
游客请输入验证码
浏览70047次