发布时间:2026/8/4 8:58:16
使用 JavaFX + Reactor 绘制函数图像并数值求解交点 —— 原理与实现 使用 JavaFX Reactor 绘制函数图像并数值求解交点 —— 原理与实现在数值计算与可视化中我们常常需要绘制函数曲线并标注其交点。本文将以一个完整的 Java 程序为例深入剖析如何利用Reactor生成数据点、JavaFX绘制曲线并通过纯数值方法符号检测 二分法求解交点最终在图上以空心圆圈和坐标标签的形式清晰显示。代码全程不依赖任何数学求导公式完全基于离散点采样与迭代逼近具有通用性强、易于扩展的特点。一、程序概览我们定义两个函数( f1(x) 3x^2 - 1 )二次函数( f2(x) 2x - 1 )一次函数目标是绘制它们在区间 ([-5, 5]) 上的图像并求出所有交点坐标在图上用空心圆标注。二、数据生成Reactor 的Flux流2.1 为何使用 ReactorReactor 提供了一套响应式编程 API其Flux可以方便地生成大量离散数据点并以声明式的方式进行处理。与传统 for 循环相比Flux更易于组合、并行处理和链式操作。2.2 代码解析doublestep0.01;doublestartX-5.0;doubleendX5.0;intcount(int)((endX-startX)/step)1;Flux.range(0,count).map(i-startXi*step).doOnNext(x-{series1.getData().add(newXYChart.Data(x,f1(x)));series2.getData().add(newXYChart.Data(x,f2(x)));}).blockLast();Flux.range(0, count)生成一个整数序列 0 到 count-1。map(i - startX i * step)将每个索引映射为对应的 ( x ) 值从而得到均匀分布的离散点。doOnNext是副作用操作在每次发出 ( x ) 时计算两个函数值并添加到 JavaFX 的Series数据列表中。blockLast()阻塞当前线程直到所有数据生成完毕。由于数据量不大约 1000 点该操作对 UI 线程影响很小。这样我们便得到了绘制曲线所需的所有点。三、绘图JavaFX 的LineChart3.1 坐标轴设置NumberAxisxAxisnewNumberAxis();xAxis.setLowerBound(-5);xAxis.setUpperBound(5);xAxis.setAutoRanging(false);固定 x 轴范围确保定义域完整显示。y 轴则自动适应数据范围。3.2 创建图表与系列LineChartNumber,NumberchartnewLineChart(xAxis,yAxis);XYChart.SeriesNumber,Numberseries1newXYChart.Series();series1.setName(f1(x) 3x² - 1);LineChart会按照数据点顺序连接成折线由于步长足够小0.01曲线将非常平滑。setCreateSymbols(false)禁用默认数据点符号避免干扰。3.3 添加数据在doOnNext中我们直接将计算出的数据点加入series的getData().add()该方法会在 JavaFX 应用程序线程中更新但blockLast()会阻塞 UI 线程直到所有点添加完毕这个过程只持续几十毫秒用户无感知。四、数值求解交点4.1 原理两个连续函数的交点满足 ( f_1(x) f_2(x) )等价于差值函数 ( h(x) f_1(x) - f_2(x) ) 的零点。若 ( h(x) ) 在某区间两端异号则根据介值定理该区间内必存在至少一个根。4.2 实现步骤离散采样在定义域内以步长step采样计算每个点的 ( h(x) )。符号检测遍历相邻点若h1 * h2 0则说明该区间内存在根。二分法精化对每个含根区间使用二分法Bisection Method迭代求根直到区间宽度小于给定精度1e-10。处理端点若某点 ( h(x) ) 恰好为零或绝对值极小直接视为交点。privateListdouble[]findIntersections(doublestep,doublestartX,doubleendX){Listdouble[]resultnewArrayList();intcount(int)((endX-startX)/step)1;double[]xValsnewdouble[count];double[]hValsnewdouble[count];for(inti0;icount;i){doublexstartXi*step;xVals[i]x;hVals[i]f1(x)-f2(x);}for(inti0;icount-1;i){if(hVals[i]*hVals[i1]0){doublerootbisect(xVals[i],xVals[i1]);doubleyf1(root);result.add(newdouble[]{root,y});}if(Math.abs(hVals[i])1e-12){doubleyf1(xVals[i]);result.add(newdouble[]{xVals[i],y});}}// 检查最后一点if(Math.abs(hVals[count-1])1e-12){doubleyf1(xVals[count-1]);result.add(newdouble[]{xVals[count-1],y});}returnresult;}4.3 二分法细节privatedoublebisect(doublea,doubleb){doubleeps1e-10;doublemid;intmaxIter100;for(inti0;imaxIter;i){mid(ab)/2;doublefaf1(a)-f2(a);doublefmf1(mid)-f2(mid);if(Math.abs(fm)eps)returnmid;if(fa*fm0)bmid;elseamid;}return(ab)/2;}二分法保证收敛且精度可控。对于本例只需几次迭代即可达到1e-10精度。五、交点标注自定义节点5.1 需求使用空心圆圈标记交点位置。在圆圈上方显示坐标标签避免遮挡曲线。5.2 实现为每个交点数据创建一个XYChart.Data并通过setNode设置自定义的StackPane。XYChart.DataNumber,NumberdatanewXYChart.Data(p[0],p[1]);StackPanenodenewStackPane();CirclecirclenewCircle(6);circle.setFill(null);// 空心circle.setStroke(Color.RED);circle.setStrokeWidth(2);LabellabelnewLabel(String.format((%.2f, %.2f),p[0],p[1]));label.setTextFill(Color.BLUE);label.setTranslateY(-20);// 上移node.getChildren().addAll(circle,label);data.setNode(node);5.3 为什么放在最上层先添加曲线系列series1, series2再添加交点系列使得交点绘制在曲线之上避免被覆盖。六、为什么数值解与解析解一致令 ( f_1(x) f_2(x) )[3x^2 - 1 2x - 1 \Rightarrow 3x^2 - 2x 0 \Rightarrow x0 \text{ 或 } x\frac{2}{3}]对应 y 值为 -1 和 1/3。数值解在1e-10精度下完全吻合验证了算法的正确性。这证明了在步长足够小、二分法精度足够高的情况下数值方法能可靠地逼近解析解。七、与之前学习内容的联系Context/ContextView虽未直接用于此程序但理解上下文传递有助于在更复杂的响应式流中传递调试信息。SynchronousSinkFlux.generate曾用于创建无限流而本例使用Flux.range生成有限点集两者都是 Reactor 生成数据的常用方式。Fuseable内部优化对于大量数据点可提升性能但本例数据量不大未显式使用。数值求交延续了之前对数函数导数、三角数流等数值计算的思想体现了响应式流在科学计算中的实用性。八、运行与效果运行程序后窗口显示两条平滑曲线交点处出现红色空心圆圈上方附有蓝色坐标标签清晰无遮挡。控制台无额外输出全部信息可视化。九、总结本文通过一个完整的 Java 程序展示了如何结合Reactor和JavaFX响应式生成大量离散点以绘制平滑曲线。利用数值差分法符号检测 二分法求解函数交点。自定义图表节点实现空心圆圈与标签标注。该方案不依赖解析公式可推广至任意连续函数具有广泛的应用价值。掌握这些技术将为后续的数值分析与可视化开发奠定坚实基础。完整代码publicclassFunctionPlotterextendsApplication{// 定义函数导数 f1(x) 3x² - 1privatedoublef1(doublex){return3*x*x-1;}// 定义函数直线 f2(x) 2x - 1privatedoublef2(doublex){return2*x-1;}Overridepublicvoidstart(StageprimaryStage){// 坐标轴NumberAxisxAxisnewNumberAxis();xAxis.setLabel(x);xAxis.setLowerBound(-5);xAxis.setUpperBound(5);xAxis.setAutoRanging(false);NumberAxisyAxisnewNumberAxis();yAxis.setLabel(y);yAxis.setAutoRanging(true);// 图表LineChartNumber,NumberchartnewLineChart(xAxis,yAxis);chart.setTitle(导数函数与直线交点);chart.setCreateSymbols(false);// 不显示数据点默认符号避免干扰doublestep0.01;doublestartX-5.0;doubleendX5.0;intcount(int)((endX-startX)/step)1;// 系列1f1(x)XYChart.SeriesNumber,Numberseries1newXYChart.Series();series1.setName(f1(x) 3x² - 1);// 系列2f2(x)XYChart.SeriesNumber,Numberseries2newXYChart.Series();series2.setName(f2(x) 2x - 1);// 使用 Reactor 生成数据点Flux.range(0,count).map(i-startXi*step).doOnNext(x-{series1.getData().add(newXYChart.Data(x,f1(x)));series2.getData().add(newXYChart.Data(x,f2(x)));}).blockLast();// ---- 数值求交点 ----Listdouble[]intersectionsfindIntersections(step,startX,endX);// 交点系列自定义节点空心圆圈 坐标标签XYChart.SeriesNumber,NumberintersectionSeriesnewXYChart.Series();intersectionSeries.setName(交点);for(double[]p:intersections){XYChart.DataNumber,NumberdatanewXYChart.Data(p[0],p[1]);// 自定义节点空心圆 标签StackPanenodenewStackPane();CirclecirclenewCircle(6);circle.setFill(null);// 空心circle.setStroke(Color.RED);circle.setStrokeWidth(2);LabellabelnewLabel(String.format((%.2f, %.2f),p[0],p[1]));label.setTextFill(Color.BLUE);label.setStyle(-fx-font-size: 12px; -fx-font-weight: bold;);label.setTranslateY(-20);// 标签上移避免遮挡node.getChildren().addAll(circle,label);data.setNode(node);intersectionSeries.getData().add(data);}// 添加所有系列到图表先添加曲线再添加交点保证交点在最上层chart.getData().addAll(series1,series2,intersectionSeries);// 可选设置交点系列默认样式透明以防默认样式干扰intersectionSeries.getNode().setStyle(-fx-stroke: transparent; -fx-background-color: transparent;);// 显示窗口ScenescenenewScene(chart,800,600);primaryStage.setScene(scene);primaryStage.show();}/** * 数值求解交点差值函数 h(x)f1(x)-f2(x) 的零点 */privateListdouble[]findIntersections(doublestep,doublestartX,doubleendX){Listdouble[]resultnewArrayList();intcount(int)((endX-startX)/step)1;double[]xValsnewdouble[count];double[]hValsnewdouble[count];for(inti0;icount;i){doublexstartXi*step;xVals[i]x;hVals[i]f1(x)-f2(x);}for(inti0;icount-1;i){doubleh1hVals[i];doubleh2hVals[i1];if(h1*h20){doublerootbisect(xVals[i],xVals[i1]);doubleyf1(root);result.add(newdouble[]{root,y});}// 处理恰好为零的点if(Math.abs(h1)1e-12){doubleyf1(xVals[i]);result.add(newdouble[]{xVals[i],y});}}if(Math.abs(hVals[count-1])1e-12){doubleyf1(xVals[count-1]);result.add(newdouble[]{xVals[count-1],y});}returnresult;}/** * 二分法求根精度 1e-10 */privatedoublebisect(doublea,doubleb){doubleeps1e-10;doublemid;intmaxIter100;for(inti0;imaxIter;i){mid(ab)/2;doublefaf1(a)-f2(a);doublefmf1(mid)-f2(mid);if(Math.abs(fm)eps)returnmid;if(fa*fm0)bmid;elseamid;}return(ab)/2;}publicstaticvoidmain(String[]args){launch(args);}}

相关新闻

2026/8/4 8:58:16

开源正在重塑AI的权力版图——从美国科技巨头的集体转向说起

2026年7月,硅谷发生了一件耐人寻味的事。 英伟达CEO黄仁勋在X平台上发布了人生第一条推文。推文附上一封公开信,标题是《开放权重与美国在AI领域的领导地位》。签署方包括英伟达、微软、Meta、IBM、Hugging Face、Mistral AI等25家科技公司和机构。此后…

2026/8/4 8:58:15

写了一个全功能的 RocketMQ .NET 客户端:EventHorizon.RocketMQ

目录 前言功能概览它不是官方客户端的替代品快速接入 先启动本地测试环境gRPC:通过 Proxy 连接 RocketMQ 5Remoting:通过 NameServer 发现 Broker多集群或多实例 发送消息消费消息 gRPC 的消费模型 PushConsumer classic Remoting 的消费模型 PushConsu…

2026/8/4 9:53:19

AES-256文件加密工具AesSafe详解与实践指南

1. 项目概述 AesSafe是一款基于AES加密算法的文件/文件夹安全保护工具,它能够帮助用户对敏感数据进行可靠的加密存储。作为一名长期关注数据安全领域的开发者,我在实际工作中经常遇到需要临时加密项目文件或客户资料的需求,市面上的加密工具要…

2026/8/4 9:53:19

SSM+Vue驾校管理系统设计与智能排班算法实践

1. 项目背景与核心价值 驾校培训管理系统作为典型的行业信息化解决方案,在2026届计算机相关专业毕业设计中持续保持高热度的选题方向。这个基于SSMVue技术栈的驾校管理系统设计,本质上是要解决传统驾校业务中存在的四大痛点:学员档案管理混乱…

2026/8/4 9:53:19

GetQzonehistory快速完整指南:三步轻松备份QQ空间所有历史记录

GetQzonehistory快速完整指南:三步轻松备份QQ空间所有历史记录 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 还在为那些承载青春记忆的QQ空间说说不小心丢失而担心吗&…

2026/8/4 9:53:19

ncmdumpGUI:免费Windows工具,轻松解密网易云音乐NCM格式文件

ncmdumpGUI:免费Windows工具,轻松解密网易云音乐NCM格式文件 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 还在为网易云音乐下载的NC…

2026/8/4 9:53:19

Spring Boot整合Apollo配置中心实战与优化

1. Spring Boot 整合 Apollo 配置中心实战指南在微服务架构盛行的当下,配置中心已成为系统不可或缺的基础组件。作为Java生态中最主流的应用框架,Spring Boot与携程开源的Apollo配置中心组合,能够完美解决分布式环境下的配置管理难题。我在多…

2026/8/4 9:48:19

Outlook启动故障排查与修复全指南

1. 问题现象与初步诊断 当你在工作日早晨匆忙打开Outlook准备处理邮件时,突然弹出一条错误提示:"无法启动Microsoft Outlook。无法打开Outlook窗口。无法打开此文件夹集合。客户端操作失败。"这种突如其来的故障会让任何职场人都心头一紧。作为…

2026/8/3 21:14:30

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/4 0:02:01

dealsea是什么?跨境卖家必知的美国deal站入门指南

说实话,第一次听说美国这个老牌折扣网站的跨境卖家,十个有八个会问同一个问题:这个平台到底是干嘛的?我见过一个做家居出口的朋友,他在亚马逊上月销二十万美金,却从来没用过它。我给他看了首页——一屏一屏…

2026/8/3 22:40:58

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/3 13:26:41

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/3 16:43:13

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…