likeRunner/BEFORE_AFTER.md
pythagodzilla 07cb1304d2 init
2026-03-19 17:57:03 +08:00

12 KiB
Raw Permalink Blame History

代码重构前后对比

整体改进

原项目问题

❌ 每次调用都重新创建对象(浪费资源,状态丢失)
❌ 流程不清晰,难以扩展
❌ 职责混乱,不知道在哪里插入新功能
❌ 数据模型不完整(缺少中间状态的定义)
❌ 无法直观看出数据在各步骤间如何流动

改进后的特点

✅ 对象复用(一次初始化,重复使用)
✅ 清晰的4步数据流每步职责明确
✅ 易于扩展(预留位置清楚标记)
✅ 完整的数据模型(每步都有输出定义)
✅ 充分的注释和伪代码(易于理解和修改)

具体对比

对比1主程序入口

原代码 (Main.kt)

fun main() {
}  // 空的,什么都没有

新代码 (Main.kt)

fun main() {
    // 1. 加载样本轨迹
    val route = sampleRoute
    
    // 2. 创建模拟器(只创建一次)
    val simulator = TrajectorySimulator(route)
    
    // 3. 配置参数
    simulator.setPhysicsParams(...)
    simulator.setNoiseParams(...)
    
    // 4. 模拟循环(逐时间步调用)
    for (time in 0.0..duration step 0.1) {
        val motionState = simulator.simulate(time)
        println(motionState)
    }
}

改进:清晰展示了如何使用,每个步骤有注释说明


对比2主处理流程

原代码 (Runner.getCoordinate)

class Runner(val route: List<MetaCoordinate>) {
    fun getCoordinate(time: Double): Coordinate {
        val path = PathLinearize(route)        // ❌ 每次都创建
        val physicEngine = RunnerPhysic()      // ❌ 每次都创建
        val noiseEngine = PathNoiseEngine()    // ❌ 每次都创建

        val distance = physicEngine.getDistance(time)
        val coordinate = path.getPointDistance(distance)
        val finalCoordinate = noiseEngine.applyNoise(coordinate.lat, coordinate.lon, physicEngine)

        return finalCoordinate
    }
}

问题

  • 每次都重新创建对象,浪费资源
  • NoiseEngine 中的漂移状态会丢失
  • 流程混乱,无法清晰看出数据如何流转
  • 返回值类型混乱Coordinate vs 其他)

新代码 (TrajectorySimulator.simulate)

class TrajectorySimulator(route: List<MetaCoordinate>) {
    // 一次初始化,重复使用
    private val pathInterpolator: PathInterpolator = PathInterpolator(route)
    private val physicsEngine: RunnerPhysics = RunnerPhysics()
    private val noiseProcessor: NoiseProcessor = NoiseProcessor()

    fun simulate(time: Double): MotionState {
        // ════════════════════════════════════════════
        // 步骤1计算物理状态
        // ════════════════════════════════════════════
        val physicsState = physicsEngine.calculate(time)  // ✅ 返回 PhysicsState
        
        // ════════════════════════════════════════════
        // 步骤2路径插值
        // ════════════════════════════════════════════
        val rawCoordinate = pathInterpolator.interpolate(physicsState.distance)  // ✅ 返回 RawCoordinate
        
        // ════════════════════════════════════════════
        // 步骤3添加噪声
        // ════════════════════════════════════════════
        val noisyCoordinate = noiseProcessor.applyNoise(rawCoordinate, physicsState)  // ✅ 返回 NoisyCoordinate
        
        // ════════════════════════════════════════════
        // 步骤4组装最终状态
        // ════════════════════════════════════════════
        return MotionState(...)  // ✅ 返回完整的 MotionState
    }
}

改进

  • 对象复用,提高效率
  • 4步流程清晰每步职责明确
  • 每步都有明确的输入输出类型
  • 易于理解和调试

对比3坐标数据模型

原代码

// 只有两个坐标类,中间状态混乱
data class Coordinate(val lon: Double, val lat: Double, val time: Double)
data class MetaCoordinate(val lon: Double, val lat: Double)

新代码

// 完整的数据流定义
data class MetaCoordinate(val lon: Double, val lat: Double)  // 原始轨迹点

data class RawCoordinate(val lon: Double, val lat: Double)  // 无噪声插值点

data class NoisyCoordinate(
    val lon: Double,
    val lat: Double,
    val gpsError: Double  // 记录噪声大小
)

data class Coordinate(val lon: Double, val lat: Double, val time: Double)  // 带时间的坐标

改进

  • 每个数据流阶段都有明确的数据类型
  • 便于调试和理解数据的变换过程
  • 预留了噪声信息的记录

对比4物理引擎

原代码

class RunnerPhysic {
    fun getDistance(time: Double): Double {}  // ❌ 未实现,空的
}

新代码

class RunnerPhysics(
    private val totalDistance: Double = 0.0,
    private val duration: Double = 1000.0,
    private val maxVelocity: Double = 4.0
) {
    /**
     * 计算指定时间的物理状态
     * 
     * @param time 当前时间(秒)
     * @return 包含距离、速度、加速度的物理状态
     */
    fun calculate(time: Double): PhysicsState {
        // 伪代码说明:
        // 1. 计算距离
        // 2. 计算速度
        // 3. 计算加速度
        
        val distance = getDistance(time)
        val velocity = 0.0  // TODO: 实现
        val acceleration = 0.0  // TODO: 实现
        
        return PhysicsState(time, distance, velocity, acceleration)
    }
    
    fun getDistance(time: Double): Double {
        // 伪代码说明
        return 0.0  // TODO: 实现
    }
}

改进

  • 返回类型改为 PhysicsState包含完整的物理信息
  • 添加了伪代码说明实现思路
  • 添加了TODO标记清楚地标出需要实现的地方
  • 参数化了初始值(便于配置)

对比5路径插值器

原代码 (pathLinearlizer.kt)

class PathLinearize(val nodes: List<MetaCoordinate>) {
    private val segments = nodes.windowed(2).map { (a, b) ->
        val distance = haversine(a, b)
        Triple(a, b, distance)
    }

    fun haversine(node1: MetaCoordinate, node2: MetaCoordinate): Double {
        // ... 完整的Haversine算法逻辑保留
    }

    fun getPointDistance(totalDistance: Double): MetaCoordinate {
        // ... 插值逻辑
    }
}

新代码 (PathInterpolator.kt)

class PathInterpolator(val nodes: List<MetaCoordinate>) {
    private val segments = nodes.windowed(2).map { (a, b) ->
        val distance = calculateHaversineDistance(a, b)  // ✅ 改名:更清晰
        Triple(a, b, distance)
    }

    fun interpolate(totalDistance: Double): RawCoordinate {  // ✅ 改名:更直观
        // ... 同样的插值逻辑,完全保留
    }

    private fun calculateHaversineDistance(node1: MetaCoordinate, node2: MetaCoordinate): Double {
        // ✅ Haversine逻辑完全保留只改了方法名
        // 和原代码一模一样
    }
}

改进

  • 类名改为 PathInterpolator更准确
  • 方法名改为 interpolatecalculateHaversineDistance(更清晰)
  • 返回类型改为 RawCoordinate更明确
  • 核心逻辑完全保留,只改了命名

对比6噪声处理

原代码

class PathNoiseEngine(
    private val gpsErrorStdDev: Double = 0.00002,
    private val driftWeight: Double = 0.3
) {
    private val random = Random()
    private var driftLat = 0.0
    private var driftLon = 0.0

    fun applyNoise(rawLat: Double, rawLon: Double, physic: RunnerPhysic): Coordinate {
        // ... 白噪声和漂移逻辑(完全保留)
        return Coordinate(rawLon+whiteNoiseLon+driftLon, rawLat+whiteNoiseLat+driftLat, time = Double)
        // ❌ time = Double 是个错误,应该是实际时间值
    }
}

新代码 (GpsNoiseEngine.kt)

class GpsNoiseEngine(
    private val gpsErrorStdDev: Double = 0.00002,
    private val driftWeight: Double = 0.3
) {
    /**
     * 应用GPS噪声到坐标
     * 
     * 伪代码:
     * 1. 生成白噪声
     * 2. 生成漂移
     * 3. 合并噪声
     */
    fun applyNoise(
        rawLon: Double,
        rawLat: Double,
        physicsState: PhysicsState
    ): Triple<Double, Double, Double> {  // ✅ 更清晰的返回类型
        
        // 第1步白噪声逻辑完全保留
        val whiteNoiseLat = random.nextGaussian() * gpsErrorStdDev
        val whiteNoiseLon = random.nextGaussian() * gpsErrorStdDev

        // 第2步漂移逻辑完全保留
        driftLat = driftLat * 0.8 + random.nextGaussian() * gpsErrorStdDev * driftWeight
        driftLon = driftLon * 0.8 + random.nextGaussian() * gpsErrorStdDev * driftWeight

        // 第3步合并逻辑完全保留
        val finalLon = rawLon + whiteNoiseLon + driftLon
        val finalLat = rawLat + whiteNoiseLat + driftLat
        
        val totalError = sqrt((whiteNoiseLon + driftLon).pow(2) + (whiteNoiseLat + driftLat).pow(2))

        return Triple(finalLon, finalLat, totalError)  // ✅ 返回噪声大小便于记录
    }
}

新增 NoiseProcessor协调多个噪声引擎

class NoiseProcessor {
    private val gpsNoiseEngine = GpsNoiseEngine()
    // 预留位置:
    // private val velocityNoiseEngine = VelocityNoiseEngine()
    // private val accelerationNoiseEngine = AccelerationNoiseEngine()

    fun applyNoise(rawCoord: RawCoordinate, physicsState: PhysicsState): NoisyCoordinate {
        val (noisyLon, noisyLat, gpsError) = gpsNoiseEngine.applyNoise(
            rawCoord.lon, rawCoord.lat, physicsState
        )
        
        // ✅ 预留位置:
        // val velocityNoise = velocityNoiseEngine.applyNoise(physicsState.velocity)
        // val accelNoise = accelerationNoiseEngine.applyNoise(physicsState.acceleration)
        
        return NoisyCoordinate(noisyLon, noisyLat, gpsError)
    }
}

改进

  • 返回值更明确Triple 包含噪声大小)
  • 创建 NoiseProcessor 协调多个噪声引擎
  • GPS噪声算法逻辑完全保留
  • 清晰标记了预留位置供未来扩展

总结

方面 原代码 新代码
项目独立性 修改原项目 新建独立项目,原项目不动
对象管理 每次重建 一次初始化,重复使用
流程清晰度 混乱 4步清晰流程
数据模型 不完整 完整的中间状态定义
命名规范 不规范 规范统一
注释文档 充分的伪代码和说明
扩展预留 清晰标记的预留位置
核心算法 保留 完全保留

如何使用新项目

  1. 快速上手:看 Main.kt完整使用示例
  2. 理解流程:看 DATA_FLOW_GUIDE.md数据流参考
  3. 要修改代码:看 README.md各文件职责说明
  4. 要加新功能:看 GpsNoiseEngine.kt预留位置已标记