Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 879|回复: 0

java awt画风向玫瑰图及风能玫瑰图

[复制链接]

该用户从未签到

发表于 2011-9-18 13:06:03 | 显示全部楼层 |阅读模式
年风向/风能玫瑰图如下所示:一个坐标轴及四个同心团,在同心团分16个区间画弧。


月风向/风能玫瑰图如下所示:

相当图。

代码如下:
DrawWindRoseChartImpl.java代码如下:



import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.text.*;
public class DrawWindRoseChartImpl implements IDrawWindRoseChart {   
  
    private DecimalFormat df = new DecimalFormat("#00.00");   
    private int circleNumber = 4; // 圆的圈数 = 4;   
    private int space = 10; // 方向标注离图形的空隙   
    private int edgSpace = 30; // 图形周边留出的空隙大小,此空隙大小必须至少等于3 * space   
  
    public BufferedImage drawYearWindRose(int gWidth, Map< Integer, Double> map,   
            RoseChartTypeEnum chartType) throws Exception {   
        int gHeight = gWidth + edgSpace; // 加上edgSpace宽度用来写图形的标题   
        BufferedImage image = new BufferedImage(gWidth, gHeight,   
                BufferedImage.TYPE_INT_ARGB);   
        Graphics2D g2 = image.createGraphics();   
        String type = "";   
        if (chartType == RoseChartTypeEnum.YEAR_WIND_DIRECTION)   
            type = "风向";   
        else if (chartType ==RoseChartTypeEnum.YEAR_WIND_POWER) {   
            type = "风能";   
        }else{   
            throw new RuntimeException("此方法不能画所要求的风玫瑰图!");   
        }   
        String title = "年" + type + "玫瑰图";   
        g2.setBackground(Color.WHITE);   
        // 画板   
        g2.fillRect(0, 0, gWidth, gHeight);   
        // 基准点距离,当x,y坐标都为基准点距离时就是圆心   
        int centerPoint = gWidth / 2;   
        // 最大圆半径   
        int maxRadius = gWidth / 2 - edgSpace;   
        // 步长   
        double step = maxRadius / circleNumber;   
        g2.setColor(Color.BLACK);   
        // 西方向在右边,标注会占距离,所以space*2   
        g2.drawString("W", centerPoint - maxRadius - 2 * space, centerPoint);   
        // 画x轴   
        g2.drawLine(centerPoint - maxRadius, centerPoint, centerPoint   
                + maxRadius, centerPoint);   
        g2.drawString("E", centerPoint + maxRadius + space, centerPoint);   
        g2.drawString("0", centerPoint, centerPoint - maxRadius - space);   
        g2.drawString("N", centerPoint, centerPoint - maxRadius - 2 * space);   
        // 画y轴   
        g2.drawLine(centerPoint, centerPoint - maxRadius, centerPoint,   
                centerPoint + maxRadius);   
        // 南方向在下边,标注会占距离,所以space*2   
        g2.drawString("180", centerPoint - space, centerPoint + maxRadius + 2  
                * space);   
        g2.drawString("S", centerPoint, centerPoint + maxRadius + 3 * space);   
        g2.drawString(title, centerPoint - 3 * space, gHeight - space);   
        //不管是否有数据,都必须把坐标及同心圆画上   
        for (int i = 1; i <= circleNumber; i++) {   
            // step * i即为所画当前圆的半径   
            int radius = (int) Math.ceil(step * i) + 1;   
            g2.drawOval(centerPoint - radius, centerPoint - radius, radius * 2,   
                    radius * 2);   
        }   
        // 只有当有数据时,才标注圆所代表的比例及画弧   
        if (map != null && map.size() > 0) {   
            // 最大比率   
            double maxRation = Collections.max(map.values());   
            // 标注比例   
            for (int i = 1; i <= circleNumber; i++) {   
                // step * i即为所画当前圆的半径   
                int radius = (int) Math.ceil(step * i) + 1;   
                int dis = (int) (Math.cos(Math.PI / 4) * radius);   
                // 标注圆代表的比例数   
                g2.drawString(df.format(maxRation / circleNumber * i * 100)   
                        + "%", centerPoint + dis, centerPoint - dis);   
            }   
            g2.setColor(Color.RED);   
            double startAngle = 0.0;   
            double arcAngle = -22.5;   
            // 画弧   
            for (Map.Entry< Integer, Double> entry : map.entrySet()) {   
                double arcRadius = Math.rint(entry.getValue() / maxRation   
                        * maxRadius);   
                int key = entry.getKey();   
                // 即是第0风向区,-11.25~11.25   
                // 因为awt画弧时0度点与风向玫瑰图的0度点相差90度,所以给画弧的开始点集体加上90度   
                if (key == 0)   
                    startAngle = 90 + 11.25;   
                else {   
                    double angle = -key * 22.5;   
                    startAngle = angle + 90;   
                }   
                Arc2D.Double arc = new Arc2D.Double(centerPoint - arcRadius,   
                        centerPoint - arcRadius, arcRadius * 2, arcRadius * 2,   
                        startAngle, arcAngle, Arc2D.PIE);   
                // 使用awt画弧   
                g2.draw(arc);   
            }   
        }   
        g2.dispose();   
        return image;   
    }   
  
    private void drawOneWindRose(Graphics2D g2, int xOffset, int yOffset,   
            int gWidth, Map< Integer, Double> map, int month) throws Exception {   
        String title = month + "月";   
        // 同心圆圆心坐标   
        int xCenter = xOffset + gWidth / 2;   
        int yCenter = yOffset + gWidth / 2;   
        // 最大圆半径   
        int maxRadius = gWidth / 2 - edgSpace;   
        // 步长   
        double step = maxRadius / circleNumber;   
        g2.setColor(Color.BLACK);   
        // 西方向在右边,标注会占距离,所以space*2   
        g2.drawString("W", xCenter - maxRadius - 2 * space, yCenter);   
        // 画x轴   
        g2.drawLine(xCenter - maxRadius, yCenter, xCenter + maxRadius, yCenter);   
        g2.drawString("E", xCenter + maxRadius + space, yCenter);   
        g2.drawString("0", xCenter, yCenter - maxRadius - space);   
  
        g2.drawString("N", xCenter, yCenter - maxRadius - 2 * space);   
        // 画y轴   
        g2.drawLine(xCenter, yCenter - maxRadius, xCenter, yCenter + maxRadius);   
        g2.drawString("180", xCenter - space, yCenter + maxRadius + 2 * space);   
        g2.drawString("S", xCenter, yCenter + maxRadius + 3 * space);   
        g2.drawString(title, xCenter + maxRadius, yCenter - maxRadius);   
        //不管当月是否有数据,都必须把同心圆画上   
        for (int i = 1; i <= circleNumber; i++) {   
            // step * i即为所画当前圆的半径   
            int radius = (int) Math.ceil(step * i) + 1;   
            g2.drawOval(xCenter - radius, yCenter - radius, radius * 2,   
                    radius * 2);   
        }   
        // 只有当有数据时,才标注圆所代表的比例及画弧   
        if (map != null && map.size() > 0) {   
            // 最大比率   
            double maxRation = Collections.max(map.values());   
            // 标注比例   
            for (int i = 1; i <= circleNumber; i++) {   
                // step * i即为所画当前圆的半径   
                int radius = (int) Math.ceil(step * i) + 1;   
                int dis = (int) (Math.cos(Math.PI / 4) * radius);   
                // 标注圆代表的比例数   
                g2.drawString(df.format(maxRation / circleNumber * i * 100)   
                        + "%", xCenter + dis, yCenter - dis);   
            }   
            g2.setColor(Color.RED);   
            double startAngle = 0.0;   
            double arcAngle = -22.5;   
            for (Map.Entry< Integer, Double> entry : map.entrySet()) {   
                double arcRadius = Math.rint(entry.getValue() / maxRation   
                        * maxRadius);   
                int key = entry.getKey();   
                // 即是第0风向区,-11.25~11.25   
                // 因为awt画弧时0度点与风向玫瑰图的0度点相差90度,所以给画弧的开始点集体加上90度   
                if (key == 0)   
                    startAngle = 90 + 11.25;   
                else {   
                    double angle = -key * 22.5;   
                    startAngle = angle + 90;   
                }   
                Arc2D.Double arc = new Arc2D.Double(xCenter - arcRadius,   
                        yCenter - arcRadius, arcRadius * 2, arcRadius * 2,   
                        startAngle, arcAngle, Arc2D.PIE);   
                // 使用awt画弧   
                g2.draw(arc);   
            }   
        }   
    }   
  
    public BufferedImage drawMonthWindRose(int width,   
            Map< Integer, Map< Integer, Double>> map, RoseChartTypeEnum chartType)   
            throws Exception {   
        //不管有几个月的数据,都画12个图,分四行三列来显示   
        //height加上edgSpace用来显示图片的标题   
        int height = width * 4 / 3 + edgSpace;   
        // 每个月的小玫瑰图所占的宽度,每行或每列的间距为space, 列数值最大为3列,所以只有四个间距。   
        int gWidth = (width - space * 4) / 3;   
        BufferedImage image = new BufferedImage(width, height,   
                BufferedImage.TYPE_INT_ARGB);   
        Graphics2D g2 = image.createGraphics();   
        String type = "";   
        if (chartType == RoseChartTypeEnum.MONTH_WIND_DIRECTION)   
            type = "风向";   
        else if (chartType == RoseChartTypeEnum.MONTH_WIND_POWER) {   
            type = "风能";   
        }else{   
            throw new RuntimeException("此方法不能画所要求的风玫瑰图!");   
        }   
        String title = "各月的" + type + "玫瑰图";   
        // 画板   
        g2.fillRect(0, 0, width, height);   
        int count = 0;   
        int rowNo = 0;   
        int colNo = 0;   
        int xOffset = 0;   
        int yOffset = 0;   
        //不管是否有数据,都画12个图,每月一个图   
        for(int i = 1; i <= 12; i++){   
            rowNo = count / 3;   
            colNo = count % 3;   
            xOffset = colNo * (gWidth + space) + space;   
            yOffset = rowNo * (gWidth + space) + space;   
            Map< Integer, Double> dataMap = (map == null || map.size() == 0) ?  null : map.get(i);   
            drawOneWindRose(g2, xOffset, yOffset, gWidth, dataMap,   
                    i);   
            count++;   
        }   
        g2.setColor(Color.BLACK);   
        g2.drawString(title, width / 2 - 3 * space, height - 2 * space);   
        g2.dispose();   
        return image;   
    }   
  
}  

RoseChartTypeEnum代码如下所示:

public enum RoseChartTypeEnum {
  YEAR_WIND_DIRECTION,YEAR_WIND_POWER,MONTH_WIND_DIRECTION,MONTH_WIND_POWER
}


接口 IDrawWindRoseChart代码如下:

import java.awt.image.*;
import java.util.*;
public interface IDrawWindRoseChart {   
           
    /**画风向玫瑰图或风能玫瑰图,  
     * @param gWidth : BufferedImage的宽度值,因为是画圆,所以只传入一个值,高度值gHeight也使用gWidth  
     * @param map : 各扇区的数据集  
     * @param chartTypeEnum : 所画玫瑰图的类型  
     * @return   
     */   
    public BufferedImage drawMonthWindRose( int gWidth,   
            Map< Integer, Map< Integer, Double>> map , RoseChartTypeEnum chartTypeEnum ) throws Exception;   
    public BufferedImage drawYearWindRose( int gWidth,   
            Map< Integer, Double> map ,RoseChartTypeEnum chartTypeEnum) throws Exception;   
}  

如果画月风向/风能玫瑰图时,如果不一次性画十二图,还是只画那些有数据的月份的图,代码如下:

public BufferedImage drawMonthWindRose( int width,   
            Map< Integer, Map< Integer, Double>> map , RoseChartTypeEnum chartType) throws Exception {   
        int size = map.size();   
        //月风向玫瑰图每行画3个小玫瑰图,除3计算行数   
        int rowCount = size % 3 == 0 ? size /3 : (size / 3 + 1);   
        int colCount = size >= 3 ? 3 : size;   
        //如果行数刚好也是3的话,则总图的宽与高相等,高加上edgSpace用来写上图片的title   
        int height = (rowCount % 3 == 0 ? width : width / 3 * rowCount) + edgSpace;   
        width = size >= 3 ? width : width / 3 * size;   
        //每个月的小玫瑰图所占的宽度,每行或每列的间距为20, 列数值最大为3列。   
        int gWidth = (width - space * (Math.max(rowCount, colCount) + 1)) / colCount;   
        BufferedImage image = new BufferedImage(width , height ,   
                BufferedImage.TYPE_INT_ARGB);   
        Graphics2D g2 = image.createGraphics();   
        String type = "";   
        if(chartType == RoseChartTypeEnum.MONTH_WIND_DIRECTION )   
            type =  "风向";   
        else if(chartType == RoseChartTypeEnum.MONTH_WIND_POWER){   
            type =   "风能";   
        }   
        String title = "各月的" + type + "玫瑰图";   
        // 画板   
        g2.fillRect(0, 0, width, height);   
        int count = 0;   
        int rowNo = 0;   
        int colNo = 0;   
        int xOffset = 0;   
        int yOffset = 0;   
        for(Map.Entry< Integer, Map< Integer, Double>> entry : map.entrySet()){   
            rowNo = count / 3 ;   
            colNo = count % 3 ;   
            xOffset = colNo * (gWidth + space) + space;   
            yOffset = rowNo * (gWidth + space) + space;   
            drawOneWindRose(g2, xOffset, yOffset, gWidth, entry.getValue(), entry.getKey());   
            count++;   
        }   
        g2.setColor(Color.BLACK);   
        g2.drawString(title, width / 2 - 3 * space, height - 2 * space);   
        g2.dispose();   
        return image;   
    }  
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-11 02:50 , Processed in 0.329918 second(s), 36 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表