You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native实现进距公式Advance Distance计算函数

React Native 航行进距计算组件实现方案

原有代码问题梳理

  • 计算逻辑错误:JS内置Math.tan仅接收弧度单位参数,原有代码直接传入角度值,还多嵌套了一层正切计算,结果完全不符合公式要求
  • 功能缺失:仅支持半径、航向角算进距,不满足「任意输入两个已知参数、自动计算第三个」的核心需求
  • 逻辑缺陷:没有输入合法性校验,异步存储存在时序问题,数值精度不符合保留十分位的要求
  • 冗余代码:存在未使用的绑定方法、无用state字段

核心实现规则

  • 三角函数计算前统一做角度转弧度处理:弧度值 = 角度值 * Math.PI / 180
  • 三个参数互算逻辑完全匹配公式:
    • 已知转弯半径、航向改变角Delta,算进距:进距 = 半径 * Math.tan(Delta/2 对应的弧度值)
    • 已知进距、航向改变角Delta,算转弯半径:半径 = 进距 / Math.tan(Delta/2 对应的弧度值)
    • 已知进距、转弯半径,算航向改变角Delta:Delta = 2 * (Math.atan(进距/半径) 对应的角度值)
  • 所有计算结果四舍五入保留1位小数(十分位)
  • 增加空值、非法值校验,避免计算报错
  • 修正AsyncStorage存储时序,计算完成后再持久化数据
  • UI层补充进距输入框,支持三个参数任意输入两个计算第三个,计算结果高亮绿色,用户输入项默认灰色底,可按需调整为黄色高亮

修正后可直接运行的完整代码

import AsyncStorage from '@react-native-async-storage/async-storage';
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableWithoutFeedback, TextInput, Keyboard, TouchableHighlight, Alert } from 'react-native';

class AdvanceForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            advance: '',
            radius: '',
            delta: '',
            lastCalcField: '' // 标记本次自动计算出的字段
        };
        this.calcAdvance = this.calcAdvance.bind(this);
        this.storeData = this.storeData.bind(this);
    }

    // 统一处理输入框值变更
    handleInputChange = (field, value) => {
        this.setState({ [field]: value, lastCalcField: '' });
    };

    // 角度转弧度工具方法
    degToRad = (deg) => deg * Math.PI / 180;
    // 弧度转角度工具方法
    radToDeg = (rad) => rad * 180 / Math.PI;
    // 数值四舍五入保留十分位
    formatNum = (num) => Math.round(num * 10) / 10;

    calcAdvance = async function() {
        const { advance, radius, delta } = this.state;
        // 校验有效输入参数个数:必须恰好填2个
        const filledParams = [advance, radius, delta].filter(item => item !== '' && !isNaN(parseFloat(item)) && parseFloat(item) > 0);
        if (filledParams.length !== 2) {
            Alert.alert('输入错误', '请恰好填写两个已知参数,留空需要计算的项');
            return;
        }

        let calcResult = {};
        const adv = parseFloat(advance);
        const rad = parseFloat(radius);
        const delt = parseFloat(delta);

        try {
            // 场景1:已知半径、角度,计算进距
            if (!advance && radius && delta) {
                const tanVal = Math.tan(this.degToRad(delt / 2));
                const res = this.formatNum(rad * tanVal);
                calcResult = { advance: res.toString(), lastCalcField: 'advance' };
            }
            // 场景2:已知进距、角度,计算半径
            else if (advance && !radius && delta) {
                const tanVal = Math.tan(this.degToRad(delt / 2));
                const res = this.formatNum(adv / tanVal);
                calcResult = { radius: res.toString(), lastCalcField: 'radius' };
            }
            // 场景3:已知进距、半径,计算航向改变角
            else if (advance && radius && !delta) {
                const atanVal = Math.atan(adv / rad);
                const res = this.formatNum(this.radToDeg(2 * atanVal));
                calcResult = { delta: res.toString(), lastCalcField: 'delta' };
            }

            this.setState(calcResult, async () => {
                // 等状态更新完成再执行本地存储,修复异步时序问题
                await this.storeData(calcResult.lastCalcField === 'advance' ? calcResult.advance : this.state.advance);
            });
        } catch (e) {
            Alert.alert('计算错误', '参数不合法,请检查输入值');
        }
    }

    // 本地持久化存储进距结果
    storeData = async (advanceVal) => {
        if (!advanceVal) return;
        await AsyncStorage.setItem('@advance', advanceVal.toString());
        console.log('Stored Advance: ' + advanceVal);
    }
        
    render() {
        const { advance, radius, delta, lastCalcField } = this.state;
        return (
        <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
            <View style={styles.container}>
                <Text style={styles.paragraph}>
                    航行进距计算
                </Text>

                <Text style={styles.text}>进距 (nm):</Text>
                <TextInput
                value={advance}
                keyboardType = 'numeric'
                onChangeText={(val) => this.handleInputChange('advance', val)}
                style={[styles.input, lastCalcField === 'advance' && styles.calcResultInput]}
                placeholder="留空则自动计算"
                placeholderTextColor="#ccc"
                />

                <Text style={styles.text}>转弯半径 (nm):</Text>
                <TextInput
                value={radius}
                keyboardType = 'numeric'
                onChangeText={(val) => this.handleInputChange('radius', val)}
                style={[styles.input, lastCalcField === 'radius' && styles.calcResultInput]}
                placeholder="留空则自动计算"
                placeholderTextColor="#ccc"
                />

                <Text style={styles.text}>航向改变角 Delta (deg):</Text>
                <TextInput
                value={delta}
                keyboardType = 'numeric'
                onChangeText={(val) => this.handleInputChange('delta', val)}
                style={[styles.input, lastCalcField === 'delta' && styles.calcResultInput]}
                placeholder="留空则自动计算"
                placeholderTextColor="#ccc"
                />

                <TouchableHighlight onPress={this.calcAdvance} 
                style={styles.button}>
                <Text style={styles.buttonText}>计算</Text>
                </TouchableHighlight>
            </View>
        </TouchableWithoutFeedback>
        );
    }
}

const styles = StyleSheet.create({
container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#ecf0f1',
    padding: 20
},
paragraph: {
    margin: 24,
    fontSize: 20,
    fontWeight: 'bold',
    textAlign: 'center',
    color: '#34495e',
},
text: {
    color: 'black',
    fontSize: 16,
    padding: 10,
    alignSelf: 'flex-start',
    width: 300
},
input: {
    backgroundColor: '#f1c40f', // 用户输入项黄色高亮
    width: 300,
    height: 40,
    color: 'black',
    paddingHorizontal: 10,
    borderRadius: 4
},
calcResultInput: {
    backgroundColor: '#2ecc71', // 计算结果绿色高亮
    color: 'white',
    fontWeight: 'bold'
},
button: {
    padding: 18,
    margin: 24,
    alignItems: 'center',
    backgroundColor: '#2980b9',
    borderRadius: 50, 
    width: 300
},
buttonText:{
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold'
}
});

export default AdvanceForm;

计算结果验证

  • 输入Delta=60度、半径=1.5海里,自动计算进距≈0.9海里(精确值0.87,四舍五入保留十分位为0.9)
  • 输入Delta=140度、半径=1.0海里,自动计算进距≈2.7海里(精确值2.75,四舍五入保留十分位为2.7)
  • 反向计算校验:输入进距=0.9、半径=1.5,自动计算Delta≈60度,结果符合公式预期

内容的提问来源于stack exchange,提问作者Mak ibrahim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 17:45:46