|
@@ -0,0 +1,314 @@
|
|
|
+package org.springblade.manager.utils;
|
|
|
+
|
|
|
+import org.jfree.chart.ChartFactory;
|
|
|
+import org.jfree.chart.ChartUtils;
|
|
|
+import org.jfree.chart.JFreeChart;
|
|
|
+import org.jfree.chart.annotations.XYTextAnnotation;
|
|
|
+import org.jfree.chart.axis.NumberAxis;
|
|
|
+import org.jfree.chart.axis.NumberTickUnit;
|
|
|
+import org.jfree.chart.plot.PlotOrientation;
|
|
|
+import org.jfree.chart.plot.XYPlot;
|
|
|
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
|
|
+import org.jfree.chart.ui.RectangleInsets;
|
|
|
+import org.jfree.data.xy.XYDataset;
|
|
|
+import org.jfree.data.xy.XYSeries;
|
|
|
+import org.jfree.data.xy.XYSeriesCollection;
|
|
|
+
|
|
|
+import java.awt.*;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Comparator;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 界限含水率
|
|
|
+ * @author LHB
|
|
|
+ */
|
|
|
+public class SoilTestChart {
|
|
|
+
|
|
|
+ // 定义关键数据点
|
|
|
+ private double[][] dataPoints; // 存储原始数据点
|
|
|
+ private double w_avg; // C'点含水率
|
|
|
+ private double wl; // WL含水率
|
|
|
+
|
|
|
+ public SoilTestChart(double[][] points) {
|
|
|
+ // 确保数据点按含水率排序(a点含水率最大,在最右边)
|
|
|
+ this.dataPoints = sortDataPoints(points);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按含水率排序数据点(确保a点在最右边)
|
|
|
+ private double[][] sortDataPoints(double[][] points) {
|
|
|
+ // 复制数组以避免修改原始数据
|
|
|
+ double[][] sorted = new double[points.length][2];
|
|
|
+ for (int i = 0; i < points.length; i++) {
|
|
|
+ sorted[i][0] = points[i][0]; // 含水率
|
|
|
+ sorted[i][1] = points[i][1]; // 锥入深度
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按含水率升序排序
|
|
|
+ Arrays.sort(sorted, Comparator.comparingDouble(a -> a[0]));
|
|
|
+ return sorted;
|
|
|
+ }
|
|
|
+
|
|
|
+ private XYDataset createDataset() {
|
|
|
+ // 提取排序后的点
|
|
|
+ double moistureC = dataPoints[0][0]; // C点含水率(最小)
|
|
|
+ double depthC = dataPoints[0][1]; // C点锥入深度
|
|
|
+
|
|
|
+ double moistureB = dataPoints[1][0]; // B点含水率
|
|
|
+ double depthB = dataPoints[1][1]; // B点锥入深度
|
|
|
+
|
|
|
+ double moistureA = dataPoints[2][0]; // A点含水率(最大)
|
|
|
+ double depthA = dataPoints[2][1]; // A点锥入深度
|
|
|
+
|
|
|
+ // 计算AB和AC线上h=2mm时的含水率
|
|
|
+ double w_ab = calculateWaterContent(moistureA, depthA, moistureB, depthB, 2.0);
|
|
|
+ double w_ac = calculateWaterContent(moistureA, depthA, moistureC, depthC, 2.0);
|
|
|
+
|
|
|
+ // 计算平均含水率作为C'点
|
|
|
+ w_avg = (w_ab + w_ac) / 2.0;
|
|
|
+
|
|
|
+ // 创建AC'线数据集 - 只包含A点和C'点
|
|
|
+ XYSeries seriesACPrime = new XYSeries("AC'线");
|
|
|
+ seriesACPrime.add(moistureA, depthA); // A点
|
|
|
+ seriesACPrime.add(w_avg, 2.0); // C'点
|
|
|
+
|
|
|
+ // 计算h=20mm时的含水率(WL)
|
|
|
+ wl = calculateWaterContent(moistureA, depthA, w_avg, 2.0, 20.0);
|
|
|
+
|
|
|
+ // 创建WL和WP的虚线数据集
|
|
|
+ XYSeries seriesWL = new XYSeries("WL");
|
|
|
+ seriesWL.add(wl, 0);
|
|
|
+ seriesWL.add(wl, 20);
|
|
|
+
|
|
|
+ XYSeries seriesWP = new XYSeries("WP");
|
|
|
+ seriesWP.add(w_avg, 0);
|
|
|
+ seriesWP.add(w_avg, 2);
|
|
|
+
|
|
|
+ XYSeries seriesWLHorizontal = new XYSeries("WL_H");
|
|
|
+ seriesWLHorizontal.add(0, 20);
|
|
|
+ seriesWLHorizontal.add(wl, 20);
|
|
|
+
|
|
|
+ XYSeries seriesWPHorizontal = new XYSeries("WP_H");
|
|
|
+ seriesWPHorizontal.add(0, 2);
|
|
|
+ seriesWPHorizontal.add(w_avg, 2);
|
|
|
+
|
|
|
+ // 创建原始点数据集
|
|
|
+ XYSeries seriesPoints = new XYSeries("原始点");
|
|
|
+ seriesPoints.add(moistureA, depthA); // A点
|
|
|
+ seriesPoints.add(moistureB, depthB); // B点
|
|
|
+ seriesPoints.add(moistureC, depthC); // C点
|
|
|
+
|
|
|
+ // 创建C'点数据集(单独显示)
|
|
|
+ XYSeries seriesCPrime = new XYSeries("C'点");
|
|
|
+ seriesCPrime.add(w_avg, 2.0);
|
|
|
+
|
|
|
+ // 将所有系列添加到数据集
|
|
|
+ XYSeriesCollection dataset = new XYSeriesCollection();
|
|
|
+ dataset.addSeries(seriesACPrime);
|
|
|
+ dataset.addSeries(seriesWL);
|
|
|
+ dataset.addSeries(seriesWP);
|
|
|
+ dataset.addSeries(seriesWLHorizontal);
|
|
|
+ dataset.addSeries(seriesWPHorizontal);
|
|
|
+ dataset.addSeries(seriesPoints);
|
|
|
+ dataset.addSeries(seriesCPrime);
|
|
|
+
|
|
|
+ return dataset;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算直线上给定深度对应的含水率
|
|
|
+ private double calculateWaterContent(double x1, double y1, double x2, double y2, double targetY) {
|
|
|
+ double k = (y2 - y1) / (x2 - x1);
|
|
|
+ double b = y1 - k * x1;
|
|
|
+ return (targetY - b) / k;
|
|
|
+ }
|
|
|
+
|
|
|
+ private JFreeChart createChart(XYDataset dataset) {
|
|
|
+ // 提取排序后的点
|
|
|
+ double moistureC = dataPoints[0][0]; // C点含水率(最小)
|
|
|
+ double depthC = dataPoints[0][1]; // C点锥入深度
|
|
|
+
|
|
|
+ double moistureB = dataPoints[1][0]; // B点含水率
|
|
|
+ double depthB = dataPoints[1][1]; // B点锥入深度
|
|
|
+
|
|
|
+ double moistureA = dataPoints[2][0]; // A点含水率(最大)
|
|
|
+ double depthA = dataPoints[2][1]; // A点锥入深度
|
|
|
+
|
|
|
+ // 创建折线图
|
|
|
+ JFreeChart chart = ChartFactory.createXYLineChart(
|
|
|
+ "锥入深度与含水率(h-w)关系", // 图表标题
|
|
|
+ "含水率w(%)", // x轴标签
|
|
|
+ "锥入深度h(mm)", // y轴标签
|
|
|
+ dataset, // 数据集
|
|
|
+ PlotOrientation.VERTICAL,
|
|
|
+ false, // 不显示图例
|
|
|
+ false, // 不显示提示
|
|
|
+ false // 不显示URL
|
|
|
+ );
|
|
|
+
|
|
|
+ // 调整图表边距
|
|
|
+ chart.setPadding(new RectangleInsets(10, 10, 10, 10));
|
|
|
+
|
|
|
+ // 解决中文乱码问题
|
|
|
+ chart.getTitle().setFont(new Font("宋体", Font.BOLD, 18));
|
|
|
+
|
|
|
+ // 获取图表区域对象
|
|
|
+ XYPlot plot = chart.getXYPlot();
|
|
|
+
|
|
|
+ // 设置x轴
|
|
|
+ NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
|
|
|
+ xAxis.setLabelFont(new Font("宋体", Font.BOLD, 14));
|
|
|
+ xAxis.setTickLabelFont(new Font("宋体", Font.BOLD, 12));
|
|
|
+ xAxis.setTickMarkOutsideLength(-5.0f);
|
|
|
+ xAxis.setTickMarksVisible(true);
|
|
|
+ xAxis.setAutoRangeIncludesZero(false);
|
|
|
+ // 设置x轴刻度间隔为10
|
|
|
+ xAxis.setTickUnit(new NumberTickUnit(10));
|
|
|
+ // 设置x轴范围,根据数据调整
|
|
|
+ xAxis.setRange(0, 100);
|
|
|
+
|
|
|
+ // 设置y轴
|
|
|
+ NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
|
|
|
+ yAxis.setLabelFont(new Font("宋体", Font.BOLD, 14));
|
|
|
+ yAxis.setTickLabelFont(new Font("宋体", Font.PLAIN, 12));
|
|
|
+ yAxis.setTickMarkOutsideLength(-5.0f);
|
|
|
+ yAxis.setTickMarksVisible(true);
|
|
|
+
|
|
|
+ //设置坐标轴偏移
|
|
|
+ plot.setAxisOffset(new RectangleInsets(0,0,0,0));
|
|
|
+ // 设置渲染器
|
|
|
+ XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
|
|
|
+
|
|
|
+ // AC'线 - 实线(只连接A点和C'点)
|
|
|
+ renderer.setSeriesPaint(0, Color.BLACK);
|
|
|
+ renderer.setSeriesStroke(0, new BasicStroke(2.0f));
|
|
|
+ renderer.setSeriesShapesVisible(0, false); // 不显示形状
|
|
|
+
|
|
|
+ // WL虚线 - 红色
|
|
|
+ renderer.setSeriesPaint(1, Color.BLACK);
|
|
|
+ renderer.setSeriesStroke(1, new BasicStroke(
|
|
|
+ 1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
|
|
|
+ 10.0f, new float[]{5.0f, 5.0f}, 0.0f
|
|
|
+ ));
|
|
|
+ renderer.setSeriesShapesVisible(1, false);
|
|
|
+
|
|
|
+ // WP虚线 - 绿色
|
|
|
+ renderer.setSeriesPaint(2, Color.BLACK);
|
|
|
+ renderer.setSeriesStroke(2, new BasicStroke(
|
|
|
+ 1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
|
|
|
+ 10.0f, new float[]{5.0f, 5.0f}, 0.0f
|
|
|
+ ));
|
|
|
+ renderer.setSeriesShapesVisible(2, false);
|
|
|
+
|
|
|
+ // WL水平虚线 - 红色
|
|
|
+ renderer.setSeriesPaint(3, Color.BLACK);
|
|
|
+ renderer.setSeriesStroke(3, new BasicStroke(
|
|
|
+ 1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
|
|
|
+ 10.0f, new float[]{5.0f, 5.0f}, 0.0f
|
|
|
+ ));
|
|
|
+ renderer.setSeriesShapesVisible(3, false);
|
|
|
+
|
|
|
+ // WP水平虚线 - 绿色
|
|
|
+ renderer.setSeriesPaint(4, Color.BLACK);
|
|
|
+ renderer.setSeriesStroke(4, new BasicStroke(
|
|
|
+ 1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
|
|
|
+ 10.0f, new float[]{5.0f, 5.0f}, 0.0f
|
|
|
+ ));
|
|
|
+ renderer.setSeriesShapesVisible(4, false);
|
|
|
+
|
|
|
+ // 原始点 - 不连线,只显示形状
|
|
|
+ renderer.setSeriesPaint(5, Color.BLACK);
|
|
|
+ renderer.setSeriesLinesVisible(5, false);
|
|
|
+ renderer.setSeriesShapesVisible(5, true);
|
|
|
+ renderer.setSeriesShape(5, new java.awt.geom.Ellipse2D.Double(-4, -4, 8, 8));
|
|
|
+
|
|
|
+ // C'点 - 不连线,只显示形状
|
|
|
+ renderer.setSeriesPaint(6, Color.BLACK);
|
|
|
+ renderer.setSeriesLinesVisible(6, false);
|
|
|
+ renderer.setSeriesShapesVisible(6, true);
|
|
|
+ renderer.setSeriesShape(6, new java.awt.geom.Ellipse2D.Double(-4, -4, 8, 8));
|
|
|
+
|
|
|
+ plot.setRenderer(renderer);
|
|
|
+
|
|
|
+ // 设置背景色
|
|
|
+ plot.setBackgroundPaint(Color.WHITE);
|
|
|
+ // 移除水平方向网格线
|
|
|
+ plot.setDomainGridlinesVisible(false);
|
|
|
+ // 移除垂直方向网格线
|
|
|
+ plot.setRangeGridlinesVisible(false);
|
|
|
+ // 禁用绘图区域外边框
|
|
|
+// plot.setOutlineVisible(false);
|
|
|
+
|
|
|
+ // A点标签(含水率最大,在最右边)
|
|
|
+ XYTextAnnotation aLabel = new XYTextAnnotation("A", moistureA - 1, depthA + 0.5);
|
|
|
+ aLabel.setFont(new Font("宋体", Font.BOLD, 14));
|
|
|
+ aLabel.setPaint(Color.BLACK);
|
|
|
+ plot.addAnnotation(aLabel);
|
|
|
+
|
|
|
+ // B点标签
|
|
|
+ XYTextAnnotation bLabel = new XYTextAnnotation("B", moistureB - 1, depthB + 0.5);
|
|
|
+ bLabel.setFont(new Font("宋体", Font.BOLD, 14));
|
|
|
+ bLabel.setPaint(Color.BLACK);
|
|
|
+ plot.addAnnotation(bLabel);
|
|
|
+
|
|
|
+ // C点标签(含水率最小,在最左边)
|
|
|
+ XYTextAnnotation cLabel = new XYTextAnnotation("C", moistureC - 1, depthC + 0.5);
|
|
|
+ cLabel.setFont(new Font("宋体", Font.BOLD, 14));
|
|
|
+ cLabel.setPaint(Color.BLACK);
|
|
|
+ plot.addAnnotation(cLabel);
|
|
|
+
|
|
|
+ // C'点标签
|
|
|
+ XYTextAnnotation cPrimeLabel = new XYTextAnnotation("C'", w_avg - 1, 2.0 + 0.5);
|
|
|
+ cPrimeLabel.setFont(new Font("宋体", Font.BOLD, 14));
|
|
|
+ cPrimeLabel.setPaint(Color.BLACK);
|
|
|
+ plot.addAnnotation(cPrimeLabel);
|
|
|
+
|
|
|
+ // WL标签(x轴上方)
|
|
|
+ XYTextAnnotation wlLabel = new XYTextAnnotation("WL", wl - 1, 0.5);
|
|
|
+ wlLabel.setFont(new Font("宋体", Font.BOLD, 12));
|
|
|
+ wlLabel.setPaint(Color.BLACK);
|
|
|
+ plot.addAnnotation(wlLabel);
|
|
|
+
|
|
|
+ // WP标签(x轴上方)
|
|
|
+ XYTextAnnotation wpLabel = new XYTextAnnotation("WP", w_avg - 1, 0.5);
|
|
|
+ wpLabel.setFont(new Font("宋体", Font.BOLD, 12));
|
|
|
+ wpLabel.setPaint(Color.BLACK);
|
|
|
+ plot.addAnnotation(wpLabel);
|
|
|
+
|
|
|
+ return chart;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成图表并保存为图片
|
|
|
+ public void generateChart(String filename, int width, int height) {
|
|
|
+ try {
|
|
|
+ // 创建数据集
|
|
|
+ XYDataset dataset = createDataset();
|
|
|
+
|
|
|
+ // 创建图表
|
|
|
+ JFreeChart chart = createChart(dataset);
|
|
|
+
|
|
|
+ // 保存图表为图片
|
|
|
+ ChartUtils.saveChartAsPNG(new File(filename), chart, width, height);
|
|
|
+ System.out.println("图表已保存为 " + filename);
|
|
|
+ } catch (IOException e) {
|
|
|
+ System.err.println("保存图表时出错: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main11(String[] args) {
|
|
|
+ // 示例数据:二维数组,每行表示一个点 [含水率, 锥入深度]
|
|
|
+ // 注意:a点应该含水率最大,在最右边
|
|
|
+ double[][] points = {
|
|
|
+ {25.0, 5.0}, // C点(含水率最小)
|
|
|
+ {35.0, 15.0}, // B点
|
|
|
+ {45.0, 25.0} // A点(含水率最大)
|
|
|
+ };
|
|
|
+
|
|
|
+ // 创建图表生成器
|
|
|
+ SoilTestChart generator = new SoilTestChart(points);
|
|
|
+
|
|
|
+ // 生成图表并保存为图片(不显示GUI窗口)
|
|
|
+ generator.generateChart("SoilTestChart.png", 500, 600);
|
|
|
+ }
|
|
|
+}
|