From 99807cb5e6d38155e800d4b6eeaba5db6836e4ef Mon Sep 17 00:00:00 2001 From: ApsisRS contributors Date: Fri, 2 Oct 2026 01:14:59 +0800 Subject: [PATCH] docs: bilingual comments for the error types, links and mesh The error modules across the remaining crates share a shape, so one table covers them all. Also the inter-satellite link geometry and the mesh connectivity analysis, including the Menger and Kosaraju notes. --- crates/network/apsis-access/src/error.rs | 16 ++++++++ crates/network/apsis-handover/src/error.rs | 12 ++++++ crates/network/apsis-isl/src/batch.rs | 9 +++++ crates/network/apsis-isl/src/geometry.rs | 24 ++++++++++++ crates/network/apsis-isl/src/link.rs | 39 +++++++++++++++++++ crates/network/apsis-mesh/src/connectivity.rs | 31 +++++++++++++++ crates/network/apsis-topology/src/error.rs | 18 +++++++++ crates/sim/apsis-scenario/src/error.rs | 2 + crates/sim/apsis-sim/src/error.rs | 12 ++++++ 9 files changed, 163 insertions(+) diff --git a/crates/network/apsis-access/src/error.rs b/crates/network/apsis-access/src/error.rs index a982681..32f0d79 100644 --- a/crates/network/apsis-access/src/error.rs +++ b/crates/network/apsis-access/src/error.rs @@ -3,20 +3,34 @@ use core::fmt; /// The category of an access error. +/// +/// 接入错误的类别。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum AccessErrorKind { /// The station or its mask is not usable. + /// + /// 地面站或其遮蔽角不可用。 InvalidStation, /// The sampling step is not positive and finite. + /// + /// 采样步长非正或非有限。 InvalidSampleStep, /// The crossing tolerance is not positive and finite. + /// + /// 交叉容差非正或非有限。 InvalidTolerance, /// The search interval is empty or not ordered. + /// + /// 搜索区间为空或次序不对。 InvalidInterval, /// The sample sequence is not in increasing time order. + /// + /// 样本序列未按时间递增排列。 UnorderedSamples, /// A supplied satellite position is not usable. + /// + /// 所提供的卫星位置不可用。 InvalidPosition, } @@ -35,6 +49,8 @@ impl fmt::Display for AccessErrorKind { } /// A failure while finding access windows. +/// +/// 查找可见性窗口时发生的失败。 #[derive(Debug, Clone, PartialEq, Eq)] pub struct AccessError { kind: AccessErrorKind, diff --git a/crates/network/apsis-handover/src/error.rs b/crates/network/apsis-handover/src/error.rs index fe6d62f..f4d5c4d 100644 --- a/crates/network/apsis-handover/src/error.rs +++ b/crates/network/apsis-handover/src/error.rs @@ -3,16 +3,26 @@ use core::fmt; /// The category of a handover error. +/// +/// 切换错误的类别。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum HandoverErrorKind { /// The candidate list is empty. + /// + /// 候选列表为空。 NoCandidates, /// The same satellite appears more than once in the candidate list. + /// + /// 同一卫星在候选列表中出现多次。 DuplicateSatellite, /// A quality value is outside its range or not finite. + /// + /// 某质量值超出取值范围或非有限。 InvalidQuality, /// A policy parameter is not usable. + /// + /// 某策略参数不可用。 InvalidPolicy, } @@ -29,6 +39,8 @@ impl fmt::Display for HandoverErrorKind { } /// A failure while making a handover decision. +/// +/// 作出切换决策时发生的失败。 #[derive(Debug, Clone, PartialEq, Eq)] pub struct HandoverError { kind: HandoverErrorKind, diff --git a/crates/network/apsis-isl/src/batch.rs b/crates/network/apsis-isl/src/batch.rs index 63b8f1f..859445d 100644 --- a/crates/network/apsis-isl/src/batch.rs +++ b/crates/network/apsis-isl/src/batch.rs @@ -21,6 +21,14 @@ use apsis_math::{Vec3, parallel::map_index}; /// /// A pair whose test is undefined, because a position is not finite or the /// body radius is not positive, yields `false`. +/// +/// 按顺序返回各位置有序对的可见性。 +/// +/// 结果按行主序:位于 `row * positions.len() + column` 的元素是 +/// `positions[row]` 对 `positions[column]` 的可见性。卫星对自身总可见, +/// 这提示调用方跳过对角线。 +/// +/// 测试未定义的点对(位置非有限或天体半径非正)给出 `false`。 pub fn visibility_matrix(positions: &[Vec3], body_radius: f64) -> Vec { let len = positions.len(); let mut matrix = vec![false; len * len]; @@ -34,6 +42,7 @@ pub fn visibility_matrix(positions: &[Vec3], body_radius: f64) -> Vec { } /// Returns the visibility of every ordered pair of positions, across several +/// 跨多个线程返回各位置有序对的可见性。 /// threads. /// /// The result matches [`visibility_matrix`] element for element and in the diff --git a/crates/network/apsis-isl/src/geometry.rs b/crates/network/apsis-isl/src/geometry.rs index 5115033..3c1cf6c 100644 --- a/crates/network/apsis-isl/src/geometry.rs +++ b/crates/network/apsis-isl/src/geometry.rs @@ -12,6 +12,13 @@ use apsis_math::Vec3; /// blocking body lies between the terminals. /// /// Returns `None` when either point is not finite. +/// +/// 返回原点到两点连线的最短距离。 +/// +/// 最近点落在两端之间时它是垂距,否则是到较近一端的距离。对星间链路 +/// 而言前一种情形是要紧的,因为遮挡天体位于两端之间。 +/// +/// 任一点非有限时返回 `None`。 pub fn closest_approach_to_centre(first: Vec3, second: Vec3) -> Option { if !first.is_finite() || !second.is_finite() { return None; @@ -39,6 +46,13 @@ pub fn closest_approach_to_centre(first: Vec3, second: Vec3) -> Option { /// /// Returns `None` when either position is not finite or the body radius is /// not positive. +/// +/// 当两颗卫星能越过该天体互相可见时返回 `true`。 +/// +/// 判据是两位置之间的线段是否保持在给定半径的球体之外。恰好擦过表面 +/// 的链路被视为通畅,因为该极限即几何地平线。 +/// +/// 任一位置非有限或天体半径非正时返回 `None`。 pub fn mutual_visibility(first: Vec3, second: Vec3, body_radius: f64) -> Option { if !body_radius.is_finite() || body_radius <= 0.0 { return None; @@ -57,6 +71,14 @@ pub fn mutual_visibility(first: Vec3, second: Vec3, body_radius: f64) -> Option< /// or when the body radius is not usable. A cell that reports its own /// position for both ends has no link, so that case is rejected rather than /// returned with a zero range. +/// +/// 返回两颗卫星之间链路的完整几何。 +/// +/// 各方向是自每颗卫星指向对方的单位矢量。其中含对中心的最接近距离,使 +/// 调用方能判断该链路有多少余量。 +/// +/// 任一位置非有限、两者重合或天体半径不可用时返回 `None`。两端回报 +/// 自身位置的单元没有链路,故该情形被拒绝而非以零距离返回。 pub fn link_geometry(first: Vec3, second: Vec3, body_radius: f64) -> Option { if !body_radius.is_finite() || body_radius < 0.0 { return None; @@ -80,6 +102,8 @@ pub fn link_geometry(first: Vec3, second: Vec3, body_radius: f64) -> Option f64 { self.centre_distance_km - body_radius } /// Returns `true` when the link clears the body. + /// + /// 当该链路越过天体时返回 `true`。 pub fn is_clear(&self, body_radius: f64) -> bool { self.centre_distance_km >= body_radius } @@ -47,27 +69,44 @@ impl LinkGeometry { /// unavailable are kept separate, because routing across a constellation has /// to distinguish a link that is geometrically blocked from one that is /// merely not established yet. +/// +/// 某一瞬时链路的状态。 +/// +/// 链路或承载业务或否。链路不可用的各种原因分开保留,因为在星座上路由 +/// 须区分被几何遮挡的链路与尚未建立的链路。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LinkState { /// The link is geometrically clear and may be used. + /// + /// 该链路几何上通畅,可以使用。 Available, /// The Earth blocks the line between the two satellites. + /// + /// 地球遮挡两颗卫星之间的连线。 Blocked, /// The Sun is within the field of view of one of the terminals, so an /// optical link cannot be used. + /// + /// 太阳位于某一终端的视场内,故该光链路不可用。 SunInField, /// The link is clear but is not established, for example because it has /// not yet been acquired or its capacity is exhausted. + /// + /// 该链路通畅但尚未建立,例如尚未捕获或其容量已耗尽。 NotEstablished, } impl LinkState { /// Returns `true` when the link may carry traffic. + /// + /// 当该链路可承载业务时返回 `true`。 pub const fn is_usable(self) -> bool { matches!(self, Self::Available) } /// Returns a short name for the state. + /// + /// 返回该状态的简称。 pub const fn name(self) -> &'static str { match self { Self::Available => "available", diff --git a/crates/network/apsis-mesh/src/connectivity.rs b/crates/network/apsis-mesh/src/connectivity.rs index 92ce1cf..59c45d7 100644 --- a/crates/network/apsis-mesh/src/connectivity.rs +++ b/crates/network/apsis-mesh/src/connectivity.rs @@ -9,6 +9,13 @@ use apsis_topology::Topology; /// hops. The result is in node order. /// /// Returns an empty vector when the node is out of range. +/// +/// 沿边的方向返回自某节点可达的节点集合。 +/// +/// 起点节点被包含在内,因为节点经零跳路径可达自身。结果按节点次序 +/// 排列。 +/// +/// 节点越界时返回空向量。 pub fn reachable_from(topology: &Topology, source: usize) -> Vec { if source >= topology.node_count() { return Vec::new(); @@ -43,6 +50,18 @@ pub fn reachable_from(topology: &Topology, source: usize) -> Vec { /// Returns `Some(0)` when no path exists, and `None` when either node is out /// of range or the two nodes are the same, for which the question is not /// defined. +/// +/// 返回两节点之间相互独立的路径条数。 +/// +/// 两条路径在不含公共边时相互独立。依 Menger 定理,该条数即使这两节点 +/// 断连所需移除的最少边数,故即该连接可承受的链路失效次数。 +/// +/// 该值以两节点之间单位容量的最大流计算,采用 Ford-Fulkerson 方法的 +/// Edmonds-Karp 变体,每步沿最短增广。对卫星网这样的小图它既快又 +/// 精确。 +/// +/// 不存在路径时返回 `Some(0)`;任一节点越界或两节点相同(此时该问题 +/// 无定义)时返回 `None`。 pub fn edge_connectivity(topology: &Topology, source: usize, destination: usize) -> Option { if source >= topology.node_count() || destination >= topology.node_count() { return None; @@ -125,6 +144,18 @@ pub fn edge_connectivity(topology: &Topology, source: usize, destination: usize) /// /// Source: Kosaraju's algorithm as described in Cormen et al., /// *Introduction to Algorithms*, 3rd edition, MIT Press, 2009, chapter 22. +/// +/// 返回强连通分量的数量。 +/// +/// 一个分量内每个节点都能沿边的方向到达其余每个节点时,它即强连通。 +/// 该计数是各自内部可路由的独立网络数,对含定向星间链路的卫星网而 +/// 言,它正是衡量该网由几部分构成的恰当度量。 +/// +/// 算法为 Kosaraju:一次深度优先搜索记录各节点的完成次序,再在反向 +/// 边上按完成次序的逆序做第二次搜索,输出各分量。 +/// +/// 出处:Kosaraju 算法,见 Cormen 等,*Introduction to Algorithms*, +/// 第 3 版,MIT Press,2009,第 22 章。 pub fn strongly_connected_components(topology: &Topology) -> usize { let node_count = topology.node_count(); if node_count == 0 { diff --git a/crates/network/apsis-topology/src/error.rs b/crates/network/apsis-topology/src/error.rs index 162d0a7..8afa8a0 100644 --- a/crates/network/apsis-topology/src/error.rs +++ b/crates/network/apsis-topology/src/error.rs @@ -3,22 +3,38 @@ use core::fmt; /// The category of a topology error. +/// +/// 拓扑错误的类别。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum TopologyErrorKind { /// A node index is outside the range of the graph. + /// + /// 节点下标超出该图的取值范围。 NoSuchNode, /// An edge already exists between the two nodes. + /// + /// 两节点之间已存在该边。 DuplicateEdge, /// No edge exists between the two nodes. + /// + /// 两节点之间不存在该边。 NoSuchEdge, /// A cost is not finite or not positive. + /// + /// 代价非有限或非正。 InvalidCost, /// The series is empty. + /// + /// 该序列为空。 EmptySeries, /// The times in a series are not strictly increasing. + /// + /// 序列中的时刻非严格递增。 UnorderedTimes, /// A time is not finite. + /// + /// 某时刻非有限。 InvalidTime, } @@ -38,6 +54,8 @@ impl fmt::Display for TopologyErrorKind { } /// A failure while building or querying a topology. +/// +/// 构建或查询拓扑时发生的失败。 #[derive(Debug, Clone, PartialEq, Eq)] pub struct TopologyError { kind: TopologyErrorKind, diff --git a/crates/sim/apsis-scenario/src/error.rs b/crates/sim/apsis-scenario/src/error.rs index 8354e82..d58c69d 100644 --- a/crates/sim/apsis-scenario/src/error.rs +++ b/crates/sim/apsis-scenario/src/error.rs @@ -3,6 +3,8 @@ use core::fmt; /// The category of a scenario error. +/// +/// 场景错误的类别。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum ScenarioErrorKind { diff --git a/crates/sim/apsis-sim/src/error.rs b/crates/sim/apsis-sim/src/error.rs index d8248dd..cc82311 100644 --- a/crates/sim/apsis-sim/src/error.rs +++ b/crates/sim/apsis-sim/src/error.rs @@ -3,14 +3,22 @@ use core::fmt; /// The category of a simulation error. +/// +/// 仿真错误的类别。 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum SimulationErrorKind { /// The scenario is not usable. + /// + /// 该场景不可用。 InvalidScenario, /// The scheduled resources do not form a usable set. + /// + /// 所调度的资源未构成可用的集合。 InvalidResources, /// A scheduled placement does not match the task it names. + /// + /// 某处放置与其所指名的任务不匹配。 InconsistentPlan, } @@ -26,6 +34,8 @@ impl fmt::Display for SimulationErrorKind { } /// A failure while preparing or starting a simulation. +/// +/// 准备或启动仿真时发生的失败。 #[derive(Debug, Clone, PartialEq, Eq)] pub struct SimulationError { kind: SimulationErrorKind, @@ -41,6 +51,8 @@ impl SimulationError { } /// Attaches a description of what caused the failure. + /// + /// 附加对导致该失败之事的说明。 pub fn with_detail(mut self, detail: impl Into) -> Self { self.detail = Some(detail.into()); self