|
@@ -0,0 +1,217 @@
|
|
|
+package org.springblade.manager.utils;
|
|
|
+
|
|
|
+import com.mixsmart.utils.RegexUtils;
|
|
|
+import org.jfree.chart.ChartFactory;
|
|
|
+import org.jfree.chart.ChartUtils;
|
|
|
+import org.jfree.chart.JFreeChart;
|
|
|
+import org.jfree.chart.axis.CategoryAxis;
|
|
|
+import org.jfree.chart.axis.NumberAxis;
|
|
|
+import org.jfree.chart.axis.NumberTickUnit;
|
|
|
+import org.jfree.chart.plot.CategoryPlot;
|
|
|
+import org.jfree.chart.plot.DatasetRenderingOrder;
|
|
|
+import org.jfree.chart.plot.PlotOrientation;
|
|
|
+import org.jfree.chart.renderer.category.LineAndShapeRenderer;
|
|
|
+import org.jfree.chart.ui.RectangleInsets;
|
|
|
+import org.jfree.data.category.DefaultCategoryDataset;
|
|
|
+
|
|
|
+import java.awt.*;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 筛分分析图表生成工具类
|
|
|
+ */
|
|
|
+public class SieveAnalysisChart {
|
|
|
+ private double[][] data;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构造函数
|
|
|
+ * @param data 筛分分析数据,格式: {{筛孔尺寸, 通过率, 累计筛余率, 第二种数据下限, 第二种数据上限}, ...}
|
|
|
+ */
|
|
|
+ public SieveAnalysisChart(double[][] data) {
|
|
|
+ this.data = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成筛分分析图表并保存为图片
|
|
|
+ * @param filename 输出文件名
|
|
|
+ * @param width 图片宽度
|
|
|
+ * @param height 图片高度
|
|
|
+ * @throws IOException 当保存文件出错时抛出
|
|
|
+ */
|
|
|
+ public void generateChart(String filename, int width, int height) throws IOException {
|
|
|
+ // 创建数据集 - 累计筛余率
|
|
|
+ DefaultCategoryDataset retainedDataset = new DefaultCategoryDataset();
|
|
|
+ // 创建数据集 - 通过率
|
|
|
+ DefaultCategoryDataset passingDataset = new DefaultCategoryDataset();
|
|
|
+ // 创建第二种数据 - 范围下限
|
|
|
+ DefaultCategoryDataset secondDataLowerDataset = new DefaultCategoryDataset();
|
|
|
+ // 创建第二种数据 - 范围上限
|
|
|
+ DefaultCategoryDataset secondDataUpperDataset = new DefaultCategoryDataset();
|
|
|
+
|
|
|
+ // 填充数据
|
|
|
+ for (double[] point : data) {
|
|
|
+ String sieveSize = String.valueOf(point[0]);
|
|
|
+ double retainedPercent = point[1];
|
|
|
+ double passingPercent = point[2];
|
|
|
+ double secondLower = point[3];
|
|
|
+ double secondUpper = point[4];
|
|
|
+
|
|
|
+ retainedDataset.addValue(retainedPercent, "累计筛余率", sieveSize);
|
|
|
+ passingDataset.addValue(passingPercent, "通过率", sieveSize);
|
|
|
+ secondDataLowerDataset.addValue(secondLower, "第二种数据下限", sieveSize);
|
|
|
+ secondDataUpperDataset.addValue(secondUpper, "第二种数据上限", sieveSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建图表(不显示图例)
|
|
|
+ JFreeChart chart = ChartFactory.createLineChart(
|
|
|
+ // 标题
|
|
|
+ "集料级配曲线",
|
|
|
+ // X轴标题
|
|
|
+ "筛孔尺寸(mm)",
|
|
|
+ // 不显示左侧Y轴标题
|
|
|
+ "",
|
|
|
+ // 数据集
|
|
|
+ retainedDataset,
|
|
|
+ PlotOrientation.VERTICAL,
|
|
|
+ // 不显示图例
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ false
|
|
|
+ );
|
|
|
+
|
|
|
+ // 设置中文字体,防止乱码
|
|
|
+ Font chineseFont = new Font("SimSun", Font.BOLD, 12);
|
|
|
+ chart.getTitle().setFont(new Font("SimSun", Font.BOLD, 16));
|
|
|
+
|
|
|
+ // 获取图表区域对象
|
|
|
+ CategoryPlot plot = chart.getCategoryPlot();
|
|
|
+
|
|
|
+ // 设置左侧Y轴 (累计筛余率)
|
|
|
+ NumberAxis retainedAxis = (NumberAxis) plot.getRangeAxis();
|
|
|
+ retainedAxis.setRange(0, 100);
|
|
|
+ retainedAxis.setTickUnit(new NumberTickUnit(10));
|
|
|
+ retainedAxis.setLabelFont(chineseFont);
|
|
|
+ retainedAxis.setTickLabelFont(chineseFont);
|
|
|
+ // 在轴线内侧添加标签
|
|
|
+ retainedAxis.setLabel("累计筛余率(%)");
|
|
|
+ retainedAxis.setLabelInsets(new RectangleInsets(0, 0, 0, 0));
|
|
|
+
|
|
|
+ // 创建并设置右侧Y轴 (通过率)
|
|
|
+ NumberAxis passingAxis = new NumberAxis("");
|
|
|
+ // 正常范围设置
|
|
|
+ passingAxis.setRange(0, 100);
|
|
|
+ // 反转Y轴,使100在顶部,0在底部
|
|
|
+ passingAxis.setInverted(true);
|
|
|
+ passingAxis.setTickUnit(new NumberTickUnit(10));
|
|
|
+ passingAxis.setLabelFont(chineseFont);
|
|
|
+ passingAxis.setTickLabelFont(chineseFont);
|
|
|
+ // 在轴线内侧添加标签
|
|
|
+ passingAxis.setLabel("通过率百分比(%)");
|
|
|
+ passingAxis.setLabelInsets(new RectangleInsets(0, 0, 0, 0));
|
|
|
+
|
|
|
+ // 设置X轴
|
|
|
+ CategoryAxis domainAxis = plot.getDomainAxis();
|
|
|
+ domainAxis.setLabelFont(chineseFont);
|
|
|
+ domainAxis.setTickLabelFont(chineseFont);
|
|
|
+
|
|
|
+ // 将右侧Y轴添加到图表
|
|
|
+ plot.setRangeAxis(1, passingAxis);
|
|
|
+
|
|
|
+ plot.setAxisOffset(new RectangleInsets(0,0,0,0));
|
|
|
+
|
|
|
+ // 添加通过率数据集
|
|
|
+ plot.setDataset(1, passingDataset);
|
|
|
+ // 将第二个数据集映射到第二个Y轴
|
|
|
+ plot.mapDatasetToRangeAxis(1, 1);
|
|
|
+
|
|
|
+ // 添加第二种数据范围数据集
|
|
|
+ plot.setDataset(2, secondDataLowerDataset);
|
|
|
+ plot.setDataset(3, secondDataUpperDataset);
|
|
|
+ // 映射到左侧Y轴
|
|
|
+ plot.mapDatasetToRangeAxis(2, 0);
|
|
|
+ // 映射到左侧Y轴
|
|
|
+ plot.mapDatasetToRangeAxis(3, 0);
|
|
|
+
|
|
|
+ // 设置渲染器 - 累计筛余率(实线,不显示数据点)
|
|
|
+ LineAndShapeRenderer retainedRenderer = (LineAndShapeRenderer) plot.getRenderer();
|
|
|
+ // 不显示数据点
|
|
|
+ retainedRenderer.setDefaultShapesVisible(false);
|
|
|
+ retainedRenderer.setSeriesPaint(0, Color.BLACK);
|
|
|
+ // 设置渲染器 - 通过率(实线,不显示数据点)
|
|
|
+ LineAndShapeRenderer passingRenderer = new LineAndShapeRenderer();
|
|
|
+ // 不显示数据点
|
|
|
+ passingRenderer.setDefaultShapesVisible(false);
|
|
|
+ passingRenderer.setSeriesPaint(0, Color.BLACK);
|
|
|
+ plot.setRenderer(1, passingRenderer);
|
|
|
+
|
|
|
+ // 设置渲染器 - 第二种数据范围(虚线,不显示数据点)
|
|
|
+ LineAndShapeRenderer secondLowerRenderer = new LineAndShapeRenderer();
|
|
|
+ // 不显示数据点
|
|
|
+ secondLowerRenderer.setDefaultShapesVisible(false);
|
|
|
+
|
|
|
+ // 设置虚线样式
|
|
|
+ secondLowerRenderer.setSeriesStroke(0, new BasicStroke(
|
|
|
+ 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
|
|
|
+ 1.0f, new float[] {6.0f, 6.0f}, 0.0f
|
|
|
+ ));
|
|
|
+ // 设置颜色
|
|
|
+ secondLowerRenderer.setSeriesPaint(0, Color.BLACK);
|
|
|
+
|
|
|
+ LineAndShapeRenderer secondUpperRenderer = new LineAndShapeRenderer();
|
|
|
+ // 不显示数据点
|
|
|
+ secondUpperRenderer.setDefaultShapesVisible(false);
|
|
|
+ // 设置虚线样式
|
|
|
+ secondUpperRenderer.setSeriesStroke(0, new BasicStroke(
|
|
|
+ 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
|
|
|
+ 1.0f, new float[] {6.0f, 6.0f}, 0.0f
|
|
|
+ ));
|
|
|
+ // 设置颜色
|
|
|
+ secondUpperRenderer.setSeriesPaint(0, Color.BLACK);
|
|
|
+
|
|
|
+ // 设置渲染器
|
|
|
+ plot.setRenderer(2, secondLowerRenderer);
|
|
|
+ plot.setRenderer(3, secondUpperRenderer);
|
|
|
+
|
|
|
+ // 设置数据集渲染顺序,确保所有线都可见
|
|
|
+ plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
|
|
|
+
|
|
|
+ // 设置背景网格线为实线
|
|
|
+ plot.setDomainGridlineStroke(new BasicStroke(1.0f));
|
|
|
+ plot.setRangeGridlineStroke(new BasicStroke(1.0f));
|
|
|
+ plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
|
|
|
+ plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
|
|
|
+ // 确保网格线可见
|
|
|
+ plot.setDomainGridlinesVisible(true);
|
|
|
+ plot.setRangeGridlinesVisible(true);
|
|
|
+
|
|
|
+ // 设置背景颜色为白色
|
|
|
+ plot.setBackgroundPaint(Color.WHITE);
|
|
|
+
|
|
|
+ // 保存为图片文件
|
|
|
+ ChartUtils.saveChartAsPNG(new File(filename), chart, width, height);
|
|
|
+ }
|
|
|
+ public static final String FC_REG = "T\\(com.mixsmart.utils.CustomFunction\\)\\.";
|
|
|
+ /**
|
|
|
+ * 使用示例
|
|
|
+ */
|
|
|
+ public static void main11(String[] args) {
|
|
|
+ try {
|
|
|
+ // 示例数据格式: {{筛孔尺寸, 通过率, 累计筛余率, 第二种数据下限, 第二种数据上限}, ...}
|
|
|
+ double[][] data = {
|
|
|
+ {4.75, 5.0, 85.0, 0.0, 10.0},
|
|
|
+ {2.36, 25.0, 55.0, 0.0, 35.0}
|
|
|
+ };
|
|
|
+
|
|
|
+ // 创建图表生成器
|
|
|
+ SieveAnalysisChart generator = new SieveAnalysisChart(data);
|
|
|
+
|
|
|
+ // 生成图表并保存为图片
|
|
|
+ generator.generateChart("sieve_analysis_chart.png", 800, 400);
|
|
|
+ System.out.println("图表已保存为 sieve_analysis_chart.png");
|
|
|
+ } catch (IOException e) {
|
|
|
+ System.err.println("保存图表时出错: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|