Apache Commons Geometry 配置参数详解

详解 Apache Commons Geometry 1.0 的精度与容差体系(Precision.EPSILON、DoubleEquivalence、绝对误差比较)及 Maven 坐标、编译目标、JVM 堆等工程参数,均附真实回显验证。

Apache Commons GeometryApache Commons Geometry2026/10/14

Apache Commons Geometry 配置参数详解

目标:系统梳理 Apache Commons Geometry 1.0 的全部可配置项——几何精度/容差(Precision.EPSILON、DoubleEquivalence、绝对/相对误差比较)、构造参数与工程侧 Maven/JVM 参数,并给出每个参数的真实运行回显。以下命令与输出均已在 Ubuntu 22.04(JDK 17.0.20.1 + Maven 3.6.3)实测通过。

一、环境信息

本节先固定本次实测所用软硬件基线,便于读者逐项对照复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • JDK:OpenJDK 17.0.20.1
  • 构建工具:Apache Maven 3.6.3
  • 目标库:Apache Commons Geometry 1.0(org.apache.commons:commons-geometry-euclidean:1.0)
  • 示例工程目录:/opt/geo-demo(含 GeometryCheck.java 与 demo/PrecisionDemo.java 等)
  • 依赖 classpath 文件:/opt/geo-demo/cp.txt(由 mvn dependency:build-classpath 生成)

Apache Commons Geometry 是纯 Java 库,没有独立的配置文件。它的“配置”分为三类,本文按此展开:

配置类别载体典型参数生效方式
几何精度/容差代码(构造器参数)Precision.EPSILON、Precision.doubleEquivalenceOfEpsilon(...)创建 Line/Plane/Area 等对象时传入
数值比较代码(静态方法)Precision.equals(...)、compareTo(...)、round(...)直接调用
工程侧pom.xml / JVM 启动参数maven.compiler.source、-Xmx构建与运行期

二、前置条件

本文所有示例均为代码级演示,需要先具备可编译运行 Geometry 的工程。满足以下条件即可:

  1. JDK 17(Geometry 1.0 要求 Java 8+,本文用 17):java -version 实测为 17.0.20.1。
  2. Maven 3.6.3:用于解析依赖与编译。
  3. 依赖已就绪:工程 pom.xml 已引入 commons-geometry-euclidean:1.0,详见《Ubuntu 22.04 安装 Apache Commons Geometry 指南》第 4.3 节。

验证依赖可用(列出传递依赖树):

cd /opt/geo-demo
mvn -B dependency:tree

输出节选(实测首尾):

[INFO] \- org.apache.commons:commons-geometry-euclidean:jar:1.0:compile
[INFO]    +- org.apache.commons:commons-geometry-core:jar:1.0:compile
[INFO]    +- org.apache.commons:commons-numbers-core:jar:1.0:compile
[INFO]    +- org.apache.commons:commons-numbers-arrays:jar:1.0:compile
[INFO]    +- org.apache.commons:commons-numbers-angle:jar:1.0:compile
[INFO]    \- org.apache.commons:commons-numbers-quaternion:jar:1.0:compile
[INFO] BUILD SUCCESS

精度相关类全部位于 commons-numbers-core(Geometry 的精度依赖),坐标 org.apache.commons:commons-numbers-core:1.0。

三、参数查看与修改方式

几何精度参数在代码中传入,没有命令行查看入口。本库唯一的“参数清单”就是 Precision 类的公开 API,可用 javap 直接查看真实签名,作为修改依据。

查看 Precision 类的公开常量与方法:

javap -cp /opt/geo-jars/commons-numbers-core-1.0.jar org.apache.commons.numbers.core.Precision

输出:

Compiled from "Precision.java"
public final class org.apache.commons.numbers.core.Precision {
  public static final double EPSILON;
  public static final double SAFE_MIN;
  public static int compareTo(double, double, double);
  public static int compareTo(double, double, int);
  public static boolean equals(float, float);
  public static boolean equalsIncludingNaN(float, float);
  public static boolean equals(float, float, float);
  public static boolean equalsIncludingNaN(float, float, float);
  public static boolean equals(float, float, int);
  public static boolean equalsIncludingNaN(float, float, int);
  public static boolean equals(double, double);
  public static boolean equalsIncludingNaN(double, double);
  public static boolean equals(double, double, double);
  public static boolean equalsWithRelativeTolerance(double, double, double);
  public static boolean equalsIncludingNaN(double, double, double);
  public static boolean equals(double, double, int);
  public static boolean equalsIncludingNaN(double, double, int);
  public static double round(double, int);
  public static double round(double, int, java.math.RoundingMode);
  public static double representableDelta(double, double);
  public static org.apache.commons.numbers.core.Precision$DoubleEquivalence doubleEquivalenceOfEpsilon(double);
  static {};
}

查看 DoubleEquivalence(几何对象内部使用的比较器接口)的方法签名:

javap -cp /opt/geo-jars/commons-numbers-core-1.0.jar org.apache.commons.numbers.core.Precision\$DoubleEquivalence

输出:

public interface org.apache.commons.numbers.core.Precision$DoubleEquivalence {
  public default boolean eq(double, double);
  public default boolean eqZero(double);
  public default boolean lt(double, double);
  public default boolean lte(double, double);
  public default boolean gt(double, double);
  public default boolean gte(double, double);
  public default double signum(double);
  public abstract int compare(double, double);
}

要点:javap 输出即“参数清单”的权威来源。几何对象(Line、Plane、Segment、ConvexArea 等)的构造器/工厂方法都接收一个 Precision.DoubleEquivalence 参数,传入不同的容差即修改几何判定行为。

四、参数总览

本文涉及的参数汇总如下,后文逐类详解:

参数/常量类型默认值(实测)作用
Precision.EPSILONdouble 常量1.1102230246251565E-16机器精度阈值(2^-53),equals 无参比较的默认容差
Precision.SAFE_MINdouble 常量2.2250738585072014E-308最小安全规格化数,representableDelta 的下限保护
Precision.doubleEquivalenceOfEpsilon(eps)工厂方法无(参数必填)构造基于绝对误差的 DoubleEquivalence
DoubleEquivalence.eq / eqZero / lt / lte / gt / gte / signum / compare接口方法由 eps 决定几何比较谓词
Precision.equals(double, double, double)静态方法第三个参数必填绝对误差比较
Precision.equalsWithRelativeTolerance(...)静态方法参数必填相对误差比较
Precision.compareTo(double, double, double)静态方法参数必填带容差的三态比较
Precision.round(double, int)静态方法参数必填按小数位四舍五入
Precision.representableDelta(double, double)静态方法参数必填计算给定目标下可表示的增量
maven.compiler.source / targetpom 属性工程自定(本文 17)编译目标字节码版本
-XmxJVM 参数默认取机器可用堆限制堆内存(本文示例 256 MB)

💡 技术拓展:浮点比较策略不止 Commons Numbers 的“绝对误差”一种。常见策略对比——

策略原理适用场景
绝对误差|a-b| ≤ eps数值量级已知且稳定
相对误差|a-b| ≤ max(|a|,|b|)·eps数值量级跨度大(如 1e-6 与 1e6 混算)
ULP 误差|a-b| ≤ n·ulp与二进制表示精度对齐
精确比较a == b无误差传播的整数值

本文默认采用绝对误差(doubleEquivalenceOfEpsilon),因为几何示例坐标量级小且稳定;若坐标跨量级混算,可改用 Precision.equalsWithRelativeTolerance。

五、核心参数分类详解

5.1 精度常量:EPSILON 与 SAFE_MIN

Precision.EPSILON 是机器精度阈值,等于 2^-53(约 1.11e-16),是 Math.ulp(1.0) 的一半;SAFE_MIN 是最小规格化正数。实测输出:

cd /opt/geo-demo
java -Xmx256m -cp "target/classes:$(cat cp.txt)" demo.PrecisionDemo

输出节选:

[const] Precision.EPSILON  = 1.1102230246251565E-16
[const] Precision.SAFE_MIN = 2.2250738585072014E-308
[eps] eps=1e-10 eq(1.0,1.0) = true , eps=1e-4 eq(1.0,1.0) = true

解读:EPSILON 用作“无参数默认容差”的参考基准;实际使用中按业务误差预算选择更大的容差(如 1e-10、1e-6)。SAFE_MIN 主要在 representableDelta 内部作为下界保护,一般不需要手动设置。

5.2 容差工厂:doubleEquivalenceOfEpsilon

所有几何对象都通过 Precision.doubleEquivalenceOfEpsilon(eps) 获得比较器,eps 决定“两个数相差多少算相等”。实测对比不同容差对点相等判断的影响:

java -Xmx256m -cp "target/classes:$(cat cp.txt)" demo.PrecisionDemo

输出节选:

[pt-eq-strict] 1,1 vs 1,1.00001 = false
[pt-eq-loose]  1,1 vs 1,1.00001 = true
[zero-strict] eqZero(1e-5,0) = false
[zero-loose]  eqZero(1e-5,0) = true

解读:同一对点 (1,1) 与 (1, 1.00001),容差 1e-10 时判定不等,容差 1e-4 时判定相等;同理 1e-5 在严格容差下不算“零”、在宽松容差下算“零”。容差越大,越多的浮点噪声被吞掉,但过大会把本应区分的位置合并,需按业务坐标量级选择。

5.3 DoubleEquivalence 谓词:eqZero / lt / gte / signum / compare

比较器除 eq 外还提供带容差的大小判断与符号函数。实测输出:

java -Xmx256m -cp "target/classes:$(cat cp.txt)" demo.Precision3Demo

输出:

[signum] signum(-2.5)     = -1.0
[signum] signum(0.0)      = 0.0
[lt]     lt(1.0, 1.000001)= false
[gte]    gte(1.0, 1.000001)= true
[cmp]    compare(1.0, 1.000001) = 0

解读(容差 1e-6):1.0 与 1.000001 的差正好落在容差边界内,因此 lt 为 false、gte 为 true、compare 返回 0(视为相等)。若差值大于容差,compare 返回 -1/1。这类谓词被 Geometry 内部用于“点是否在直线上”“两线是否平行”等判定。

5.4 静态比较方法:equals / equalsWithRelativeTolerance / compareTo

不构造对象时可直接用静态方法做数值比较,支持绝对误差与相对误差两种口径。实测输出:

java -Xmx256m -cp "target/classes:$(cat cp.txt)" demo.Precision2Demo

输出:

[abs]   equals(1.0, 1.000000000001, 1e-9)     = true
[abs]   equals(1.0, 1.000000000001, 1e-12)    = false
[rel]   equalsWithRelativeTolerance(1000000.0, 1000001.0, 1e-6) = true
[cmp]   compareTo(1.0, 1.000000001, 1e-6)     = 0
[cmp]   compareTo(1.0, 1.000000001, 1e-10)    = -1
[rd]    round(1.23456789, 4)                  = 1.2346
[ulp]   Math.ulp(1.0)                         = 2.220446049250313E-16

解读:

  • equals(a, b, eps):绝对误差比较,1.0 与 1.000000000001 在容差 1e-9 下相等、在 1e-12 下不等。
  • equalsWithRelativeTolerance(a, b, eps):相对误差比较,1000000.0 与 1000001.0 相差 0.0001%,小于相对容差 1e-6(即 0.0001%),判定相等——这种口径适合大数比较。
  • compareTo(a, b, eps):三态比较,返回 -1/0/1。
  • round(d, n):按小数位四舍五入。

5.5 representableDelta:可表示的增量

representableDelta(reference, delta) 返回“在 reference 量级下实际可表示的 delta 步长”,用于理解浮点表示对容差的下限影响。实测输出:

[repr]   representableDelta(1.0, 1e-3) = 9.999999999998899E-4
[repr]   representableDelta(1e6, 1e-3) = 0.0010000000474974513
[ulpE6]  Math.ulp(1000000.0) = 1.1641532182693481E-10

解读:在 1.0 量级,1e-3 可被精确表示;在 1e6 量级,由于 ulp(1e6) ≈ 1.16e-10,1e-3 会被量化到最近的表示值(0.0010000000474974513)。坐标越大,浮点表示越粗,这是几何计算在大坐标场景下需要放宽容差的原因。

5.6 构造参数:precision 传入几何对象

Line/Plane/Segment/ConvexArea 等全部通过工厂方法接收 precision。以 2D 直线为例,平行判定直接受容差影响。实测输出:

java -Xmx256m -cp "target/classes:$(cat cp.txt)" demo.PrecisionDemo

输出节选:

[parallel-loose]  isParallel = true
[parallel-strict] isParallel = false
[side] offset(0,5) = -5.0
[side] offset(0,-5)= 5.0

解读:两条相差 1e-5 的“几乎平行”直线,在容差 1e-4 下判定平行,在容差 1e-10 下判定不平行;offset 的符号表示点在直线的哪一侧。3D 的 Planes.fromPoints、Planes.fromPointAndNormal 同样接收 precision 参数,行为一致。

5.7 工程侧参数:Maven 编译目标与编码

pom.xml 中的 maven.compiler.source/target 决定编译字节码版本(本文 17),project.build.sourceEncoding 决定源码编码:

grep -E "compiler.source|compiler.target|sourceEncoding" /opt/geo-demo/pom.xml

输出:

<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

解读:source/target=17 需 JDK 17 编译;UTF-8 保证含中文注释的源码可正常编译,否则 javac 会报 unmappable character。

5.8 JVM 运行参数

Geometry 库本身轻量,运行期通过 -Xmx 控制堆内存。本文示例统一使用 256 MB 堆:

java -Xmx256m -cp "target/classes:$(cat cp.txt)" demo.Geometry2DDemo

输出节选(实测首尾):

[v-add]   a.add(b)      = (4.0, 6.0)
...
[region-u]  union area = 18.0

解读:-Xmx256m 将最大堆限制为 256 MB,对几何示例(少量对象)完全够用且避免默认堆过大浪费内存;生产按数据规模可放宽到 512 MB。

六、生产配置模板

按“16GB 内存服务器、普通磁盘、批量几何计算服务”场景给出推荐配置:

配置项推荐值理由
JDK17 LTS长期支持,Geometry 1.0 实测正常
Maven 编译目标17与 JDK 一致
几何容差1e-10(坐标 ≤ 1e4);1e-6(坐标 ≥ 1e5)平衡噪声与精度,见 5.5
大数比较equalsWithRelativeTolerance(a, b, 1e-6)避免绝对误差误判
JVM 堆-Xms256m -Xmx512m服务型进程常见下限/上限
源码编码UTF-8中文环境必需

将容差、坐标量级与堆参数写入工程的方式:

mkdir -p /opt/geo-app/src/main/java

示例 pom.xml 关键片段:

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-geometry-euclidean</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>

启动脚本中固定堆参数:

java -Xms256m -Xmx512m -cp "target/classes:$(cat cp.txt)" demo.Geometry2DDemo

七、常见问题(FAQ)

Q1:容差选多大合适?

没有通用值,按坐标量级定:小坐标(如 < 1e4)用 1e-10;大坐标(如经纬度 1e6 量级)用 1e-6 或更大,否则 representableDelta 会放大误差(见 5.5 实测)。先跑一轮真实数据,把误判比例降到业务可接受范围。

Q2:Precision.DOUBLE 为什么编译报错?

Commons Numbers 1.0 的 Precision 类没有 DOUBLE 常量,只有 EPSILON(1.1102230246251565E-16)与 SAFE_MIN。需要“默认机器精度”时直接用 Precision.doubleEquivalenceOfEpsilon(Precision.EPSILON)。可用 javap 核对类成员(见三章)。

Q3:两个点明明相等,eq 却返回 false?

大概率是容差太小或坐标量级太大。先打印两者差值并与容差对比;大坐标场景改用相对误差比较(5.4 节)。

Q4:mvn compile 报 invalid target release: 17?

Maven 运行在低于 17 的 JDK 上。确认 mvn -version | grep "Java version",若为 8,设 JAVA_HOME 指向 JDK 17(CentOS 8 常见,见《CentOS 8 安装 Apache Commons Geometry 指南》Q1)。

Q5:运行时报 NoClassDefFoundError: Precision?

classpath 缺 commons-numbers-core。Maven 工程用 mvn dependency:build-classpath 生成完整 classpath;手动 jar 需补齐 5 个 commons-numbers-* 依赖。

八、参考链接

  1. Apache Commons Geometry 官方站点:https://commons.apache.org/proper/commons-geometry/
  2. Commons Numbers Precision 文档:https://commons.apache.org/proper/commons-numbers/javadocs/api-release/org/apache/commons/numbers/core/Precision.html
  3. Maven 中央仓库 commons-numbers-core:https://repo1.maven.org/maven2/org/apache/commons/commons-numbers-core/
  4. Apache Commons Geometry 用户指南:https://commons.apache.org/proper/commons-geometry/userguide/index.html