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入门到精通教程
查看: 358|回复: 0

[图像处理学习]java awt画风向玫瑰图及风能玫瑰图

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-28 23:55:44 | 显示全部楼层 |阅读模式
    年风向/风能玫瑰图如下所示:一个坐标轴及四个同心团,在同心团分16个区间画弧。


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

    相当图。

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


    1. import java.util.*;
    2. import java.awt.*;
    3. import java.awt.image.*;
    4. import java.awt.geom.*;
    5. import java.text.*;
    6. public class DrawWindRoseChartImpl implements IDrawWindRoseChart {   
    7.   
    8.     private DecimalFormat df = new DecimalFormat("#00.00");   
    9.     private int circleNumber = 4; // 圆的圈数 = 4;   
    10.     private int space = 10; // 方向标注离图形的空隙   
    11.     private int edgSpace = 30; // 图形周边留出的空隙大小,此空隙大小必须至少等于3 * space   
    12.   
    13.     public BufferedImage drawYearWindRose(int gWidth, Map< Integer, Double> map,   
    14.             RoseChartTypeEnum chartType) throws Exception {   
    15.         int gHeight = gWidth + edgSpace; // 加上edgSpace宽度用来写图形的标题   
    16.         BufferedImage image = new BufferedImage(gWidth, gHeight,   
    17.                 BufferedImage.TYPE_INT_ARGB);   
    18.         Graphics2D g2 = image.createGraphics();   
    19.         String type = "";   
    20.         if (chartType == RoseChartTypeEnum.YEAR_WIND_DIRECTION)   
    21.             type = "风向";   
    22.         else if (chartType ==RoseChartTypeEnum.YEAR_WIND_POWER) {   
    23.             type = "风能";   
    24.         }else{   
    25.             throw new RuntimeException("此方法不能画所要求的风玫瑰图!");   
    26.         }   
    27.         String title = "年" + type + "玫瑰图";   
    28.         g2.setBackground(Color.WHITE);   
    29.         // 画板   
    30.         g2.fillRect(0, 0, gWidth, gHeight);   
    31.         // 基准点距离,当x,y坐标都为基准点距离时就是圆心   
    32.         int centerPoint = gWidth / 2;   
    33.         // 最大圆半径   
    34.         int maxRadius = gWidth / 2 - edgSpace;   
    35.         // 步长   
    36.         double step = maxRadius / circleNumber;   
    37.         g2.setColor(Color.BLACK);   
    38.         // 西方向在右边,标注会占距离,所以space*2   
    39.         g2.drawString("W", centerPoint - maxRadius - 2 * space, centerPoint);   
    40.         // 画x轴   
    41.         g2.drawLine(centerPoint - maxRadius, centerPoint, centerPoint   
    42.                 + maxRadius, centerPoint);   
    43.         g2.drawString("E", centerPoint + maxRadius + space, centerPoint);   
    44.         g2.drawString("0", centerPoint, centerPoint - maxRadius - space);   
    45.         g2.drawString("N", centerPoint, centerPoint - maxRadius - 2 * space);   
    46.         // 画y轴   
    47.         g2.drawLine(centerPoint, centerPoint - maxRadius, centerPoint,   
    48.                 centerPoint + maxRadius);   
    49.         // 南方向在下边,标注会占距离,所以space*2   
    50.         g2.drawString("180", centerPoint - space, centerPoint + maxRadius + 2  
    51.                 * space);   
    52.         g2.drawString("S", centerPoint, centerPoint + maxRadius + 3 * space);   
    53.         g2.drawString(title, centerPoint - 3 * space, gHeight - space);   
    54.         //不管是否有数据,都必须把坐标及同心圆画上   
    55.         for (int i = 1; i <= circleNumber; i++) {   
    56.             // step * i即为所画当前圆的半径   
    57.             int radius = (int) Math.ceil(step * i) + 1;   
    58.             g2.drawOval(centerPoint - radius, centerPoint - radius, radius * 2,   
    59.                     radius * 2);   
    60.         }   
    61.         // 只有当有数据时,才标注圆所代表的比例及画弧   
    62.         if (map != null && map.size() > 0) {   
    63.             // 最大比率   
    64.             double maxRation = Collections.max(map.values());   
    65.             // 标注比例   
    66.             for (int i = 1; i <= circleNumber; i++) {   
    67.                 // step * i即为所画当前圆的半径   
    68.                 int radius = (int) Math.ceil(step * i) + 1;   
    69.                 int dis = (int) (Math.cos(Math.PI / 4) * radius);   
    70.                 // 标注圆代表的比例数   
    71.                 g2.drawString(df.format(maxRation / circleNumber * i * 100)   
    72.                         + "%", centerPoint + dis, centerPoint - dis);   
    73.             }   
    74.             g2.setColor(Color.RED);   
    75.             double startAngle = 0.0;   
    76.             double arcAngle = -22.5;   
    77.             // 画弧   
    78.             for (Map.Entry< Integer, Double> entry : map.entrySet()) {   
    79.                 double arcRadius = Math.rint(entry.getValue() / maxRation   
    80.                         * maxRadius);   
    81.                 int key = entry.getKey();   
    82.                 // 即是第0风向区,-11.25~11.25   
    83.                 // 因为awt画弧时0度点与风向玫瑰图的0度点相差90度,所以给画弧的开始点集体加上90度   
    84.                 if (key == 0)   
    85.                     startAngle = 90 + 11.25;   
    86.                 else {   
    87.                     double angle = -key * 22.5;   
    88.                     startAngle = angle + 90;   
    89.                 }   
    90.                 Arc2D.Double arc = new Arc2D.Double(centerPoint - arcRadius,   
    91.                         centerPoint - arcRadius, arcRadius * 2, arcRadius * 2,   
    92.                         startAngle, arcAngle, Arc2D.PIE);   
    93.                 // 使用awt画弧   
    94.                 g2.draw(arc);   
    95.             }   
    96.         }   
    97.         g2.dispose();   
    98.         return image;   
    99.     }   
    100.   
    101.     private void drawOneWindRose(Graphics2D g2, int xOffset, int yOffset,   
    102.             int gWidth, Map< Integer, Double> map, int month) throws Exception {   
    103.         String title = month + "月";   
    104.         // 同心圆圆心坐标   
    105.         int xCenter = xOffset + gWidth / 2;   
    106.         int yCenter = yOffset + gWidth / 2;   
    107.         // 最大圆半径   
    108.         int maxRadius = gWidth / 2 - edgSpace;   
    109.         // 步长   
    110.         double step = maxRadius / circleNumber;   
    111.         g2.setColor(Color.BLACK);   
    112.         // 西方向在右边,标注会占距离,所以space*2   
    113.         g2.drawString("W", xCenter - maxRadius - 2 * space, yCenter);   
    114.         // 画x轴   
    115.         g2.drawLine(xCenter - maxRadius, yCenter, xCenter + maxRadius, yCenter);   
    116.         g2.drawString("E", xCenter + maxRadius + space, yCenter);   
    117.         g2.drawString("0", xCenter, yCenter - maxRadius - space);   
    118.   
    119.         g2.drawString("N", xCenter, yCenter - maxRadius - 2 * space);   
    120.         // 画y轴   
    121.         g2.drawLine(xCenter, yCenter - maxRadius, xCenter, yCenter + maxRadius);   
    122.         g2.drawString("180", xCenter - space, yCenter + maxRadius + 2 * space);   
    123.         g2.drawString("S", xCenter, yCenter + maxRadius + 3 * space);   
    124.         g2.drawString(title, xCenter + maxRadius, yCenter - maxRadius);   
    125.         //不管当月是否有数据,都必须把同心圆画上   
    126.         for (int i = 1; i <= circleNumber; i++) {   
    127.             // step * i即为所画当前圆的半径   
    128.             int radius = (int) Math.ceil(step * i) + 1;   
    129.             g2.drawOval(xCenter - radius, yCenter - radius, radius * 2,   
    130.                     radius * 2);   
    131.         }   
    132.         // 只有当有数据时,才标注圆所代表的比例及画弧   
    133.         if (map != null && map.size() > 0) {   
    134.             // 最大比率   
    135.             double maxRation = Collections.max(map.values());   
    136.             // 标注比例   
    137.             for (int i = 1; i <= circleNumber; i++) {   
    138.                 // step * i即为所画当前圆的半径   
    139.                 int radius = (int) Math.ceil(step * i) + 1;   
    140.                 int dis = (int) (Math.cos(Math.PI / 4) * radius);   
    141.                 // 标注圆代表的比例数   
    142.                 g2.drawString(df.format(maxRation / circleNumber * i * 100)   
    143.                         + "%", xCenter + dis, yCenter - dis);   
    144.             }   
    145.             g2.setColor(Color.RED);   
    146.             double startAngle = 0.0;   
    147.             double arcAngle = -22.5;   
    148.             for (Map.Entry< Integer, Double> entry : map.entrySet()) {   
    149.                 double arcRadius = Math.rint(entry.getValue() / maxRation   
    150.                         * maxRadius);   
    151.                 int key = entry.getKey();   
    152.                 // 即是第0风向区,-11.25~11.25   
    153.                 // 因为awt画弧时0度点与风向玫瑰图的0度点相差90度,所以给画弧的开始点集体加上90度   
    154.                 if (key == 0)   
    155.                     startAngle = 90 + 11.25;   
    156.                 else {   
    157.                     double angle = -key * 22.5;   
    158.                     startAngle = angle + 90;   
    159.                 }   
    160.                 Arc2D.Double arc = new Arc2D.Double(xCenter - arcRadius,   
    161.                         yCenter - arcRadius, arcRadius * 2, arcRadius * 2,   
    162.                         startAngle, arcAngle, Arc2D.PIE);   
    163.                 // 使用awt画弧   
    164.                 g2.draw(arc);   
    165.             }   
    166.         }   
    167.     }   
    168.   
    169.     public BufferedImage drawMonthWindRose(int width,   
    170.             Map< Integer, Map< Integer, Double>> map, RoseChartTypeEnum chartType)   
    171.             throws Exception {   
    172.         //不管有几个月的数据,都画12个图,分四行三列来显示   
    173.         //height加上edgSpace用来显示图片的标题   
    174.         int height = width * 4 / 3 + edgSpace;   
    175.         // 每个月的小玫瑰图所占的宽度,每行或每列的间距为space, 列数值最大为3列,所以只有四个间距。   
    176.         int gWidth = (width - space * 4) / 3;   
    177.         BufferedImage image = new BufferedImage(width, height,   
    178.                 BufferedImage.TYPE_INT_ARGB);   
    179.         Graphics2D g2 = image.createGraphics();   
    180.         String type = "";   
    181.         if (chartType == RoseChartTypeEnum.MONTH_WIND_DIRECTION)   
    182.             type = "风向";   
    183.         else if (chartType == RoseChartTypeEnum.MONTH_WIND_POWER) {   
    184.             type = "风能";   
    185.         }else{   
    186.             throw new RuntimeException("此方法不能画所要求的风玫瑰图!");   
    187.         }   
    188.         String title = "各月的" + type + "玫瑰图";   
    189.         // 画板   
    190.         g2.fillRect(0, 0, width, height);   
    191.         int count = 0;   
    192.         int rowNo = 0;   
    193.         int colNo = 0;   
    194.         int xOffset = 0;   
    195.         int yOffset = 0;   
    196.         //不管是否有数据,都画12个图,每月一个图   
    197.         for(int i = 1; i <= 12; i++){   
    198.             rowNo = count / 3;   
    199.             colNo = count % 3;   
    200.             xOffset = colNo * (gWidth + space) + space;   
    201.             yOffset = rowNo * (gWidth + space) + space;   
    202.             Map< Integer, Double> dataMap = (map == null || map.size() == 0) ?  null : map.get(i);   
    203.             drawOneWindRose(g2, xOffset, yOffset, gWidth, dataMap,   
    204.                     i);   
    205.             count++;   
    206.         }   
    207.         g2.setColor(Color.BLACK);   
    208.         g2.drawString(title, width / 2 - 3 * space, height - 2 * space);   
    209.         g2.dispose();   
    210.         return image;   
    211.     }   
    212.   
    213. }  
    复制代码
    RoseChartTypeEnum代码如下所示: public enum RoseChartTypeEnum {
       YEAR_WIND_DIRECTION,YEAR_WIND_POWER,MONTH_WIND_DIRECTION,MONTH_WIND_POWER
    }
      接口 IDrawWindRoseChart代码如下:
    1. import java.awt.image.*;
    2. import java.util.*;
    3. public interface IDrawWindRoseChart {   
    4.            
    5.     /**画风向玫瑰图或风能玫瑰图,  
    6.      * @param gWidth : BufferedImage的宽度值,因为是画圆,所以只传入一个值,高度值gHeight也使用gWidth  
    7.      * @param map : 各扇区的数据集  
    8.      * @param chartTypeEnum : 所画玫瑰图的类型  
    9.      * @return   
    10.      */   
    11.     public BufferedImage drawMonthWindRose( int gWidth,   
    12.             Map< Integer, Map< Integer, Double>> map , RoseChartTypeEnum chartTypeEnum ) throws Exception;   
    13.     public BufferedImage drawYearWindRose( int gWidth,   
    14.             Map< Integer, Double> map ,RoseChartTypeEnum chartTypeEnum) throws Exception;   
    15. }  
    复制代码
    如果画月风向/风能玫瑰图时,如果不一次性画十二图,还是只画那些有数据的月份的图,代码如下:
    1. public BufferedImage drawMonthWindRose( int width,   
    2.             Map< Integer, Map< Integer, Double>> map , RoseChartTypeEnum chartType) throws Exception {   
    3.         int size = map.size();   
    4.         //月风向玫瑰图每行画3个小玫瑰图,除3计算行数   
    5.         int rowCount = size % 3 == 0 ? size /3 : (size / 3 + 1);   
    6.         int colCount = size >= 3 ? 3 : size;   
    7.         //如果行数刚好也是3的话,则总图的宽与高相等,高加上edgSpace用来写上图片的title   
    8.         int height = (rowCount % 3 == 0 ? width : width / 3 * rowCount) + edgSpace;   
    9.         width = size >= 3 ? width : width / 3 * size;   
    10.         //每个月的小玫瑰图所占的宽度,每行或每列的间距为20, 列数值最大为3列。   
    11.         int gWidth = (width - space * (Math.max(rowCount, colCount) + 1)) / colCount;   
    12.         BufferedImage image = new BufferedImage(width , height ,   
    13.                 BufferedImage.TYPE_INT_ARGB);   
    14.         Graphics2D g2 = image.createGraphics();   
    15.         String type = "";   
    16.         if(chartType == RoseChartTypeEnum.MONTH_WIND_DIRECTION )   
    17.             type =  "风向";   
    18.         else if(chartType == RoseChartTypeEnum.MONTH_WIND_POWER){   
    19.             type =   "风能";   
    20.         }   
    21.         String title = "各月的" + type + "玫瑰图";   
    22.         // 画板   
    23.         g2.fillRect(0, 0, width, height);   
    24.         int count = 0;   
    25.         int rowNo = 0;   
    26.         int colNo = 0;   
    27.         int xOffset = 0;   
    28.         int yOffset = 0;   
    29.         for(Map.Entry< Integer, Map< Integer, Double>> entry : map.entrySet()){   
    30.             rowNo = count / 3 ;   
    31.             colNo = count % 3 ;   
    32.             xOffset = colNo * (gWidth + space) + space;   
    33.             yOffset = rowNo * (gWidth + space) + space;   
    34.             drawOneWindRose(g2, xOffset, yOffset, gWidth, entry.getValue(), entry.getKey());   
    35.             count++;   
    36.         }   
    37.         g2.setColor(Color.BLACK);   
    38.         g2.drawString(title, width / 2 - 3 * space, height - 2 * space);   
    39.         g2.dispose();   
    40.         return image;   
    41.     }  
    复制代码


       
         
         
          
          

            
          

            
          
         
       

      


    源码下载:http://file.javaxxz.com/2014/10/28/235544218.zip
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2025-2-26 04:06 , Processed in 0.288708 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

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