鸿蒙手写数学公式计算器开发指南 原创

进修的泡芙
发布于 2025-6-20 14:10
浏览
0收藏

鸿蒙手写数学公式计算器开发指南

一、系统架构设计

基于HarmonyOS的手写识别能力和分布式技术,我们设计了一套手写数学公式计算系统,主要功能包括:
手写识别:通过@ohos.ai.handwriting识别数学公式

实时计算:解析并计算数学表达式

分布式同步:多设备间同步计算过程和结果

历史记录:保存计算历史

协作计算:多用户同时编辑公式

!https://example.com/harmony-math-calculator-arch.png

二、核心代码实现
手写识别服务

// HandwritingRecognitionService.ets
import handwriting from ‘@ohos.ai.handwriting’;

class HandwritingRecognitionService {
private static instance: HandwritingRecognitionService;
private hwEngine: handwriting.HandwritingEngine;

private constructor() {
this.initEngine();
private initEngine(): void {

this.hwEngine = handwriting.createHandwritingEngine({
  language: 'zh-CN',
  mode: handwriting.RecognitionMode.MODE_TEXT,
  type: handwriting.ModelType.TYPE_ONLINE,
  customConfig: {
    'math_symbols': 'true',
    'formula_recognition': 'true'

});

public static getInstance(): HandwritingRecognitionService {

if (!HandwritingRecognitionService.instance) {
  HandwritingRecognitionService.instance = new HandwritingRecognitionService();

return HandwritingRecognitionService.instance;

public async recognize(strokes: handwriting.Stroke[]): Promise<string[]> {

const config: handwriting.RecognitionConfig = {
  punctuation: false,
  wordCount: 1,
  language: 'zh-CN',
  recognitionMode: handwriting.RecognitionMode.MODE_TEXT,
  extraConfig: {
    'math_mode': 'true',
    'formula_timeout': '5000'

};

const results = await this.hwEngine.recognize(strokes, config);
return results.map(result => this.normalizeMathSymbols(result.text));

private normalizeMathSymbols(text: string): string {

const symbolMap: Record<string, string> = {
  '×': '*', '÷': '/', '−': '-', '=': '=',
  '(': '(', ')': ')', '【': '[', '】': ']'
};

return text.split('').map(char => symbolMap[char] || char).join('');

}

export const hwRecognitionService = HandwritingRecognitionService.getInstance();

数学计算引擎

// MathCalculationEngine.ets
class MathCalculationEngine {
private static instance: MathCalculationEngine;

private constructor() {}

public static getInstance(): MathCalculationEngine {
if (!MathCalculationEngine.instance) {
MathCalculationEngine.instance = new MathCalculationEngine();
return MathCalculationEngine.instance;

public evaluate(expression: string): number | string {

try {
  // 安全评估数学表达式
  return this.safeEval(expression);

catch (err) {

  return '计算错误';

}

private safeEval(expr: string): number {
// 移除所有非数学字符
const safeExpr = expr.replace(/[^0-9+-*/().,]/g, ‘’);

// 使用Function构造器避免直接eval
return new Function(return ${safeExpr})();

public formatResult(value: number): string {

if (Number.isInteger(value)) {
  return value.toString();

// 保留4位小数

const rounded = Math.round(value * 10000) / 10000;

// 处理科学计数法
if (Math.abs(rounded) >= 1e6 || Math.abs(rounded) < 1e-4) {
  return rounded.toExponential(4);

return rounded.toString();

}

export const mathEngine = MathCalculationEngine.getInstance();

分布式同步服务

// DistributedCalculationService.ets
import distributedData from ‘@ohos.data.distributedData’;

class DistributedCalculationService {
private static instance: DistributedCalculationService;
private kvManager: distributedData.KVManager;
private kvStore: distributedData.KVStore;

private constructor() {
this.initDistributedKVStore();
private async initDistributedKVStore(): Promise<void> {

const config = {
  bundleName: 'com.example.mathCalculator',
  userInfo: { userId: 'currentUser' }
};

this.kvManager = distributedData.createKVManager(config);
this.kvStore = await this.kvManager.getKVStore('calculation_store', {
  createIfMissing: true
});

this.kvStore.on('dataChange', (data) => {
  this.handleDataChange(data);
});

public static getInstance(): DistributedCalculationService {

if (!DistributedCalculationService.instance) {
  DistributedCalculationService.instance = new DistributedCalculationService();

return DistributedCalculationService.instance;

public async syncCalculation(calculation: CalculationRecord): Promise<void> {

await this.kvStore.put('current_calculation', JSON.stringify(calculation));

public async syncHistory(history: CalculationRecord[]): Promise<void> {

await this.kvStore.put('calculation_history', JSON.stringify(history));

private handleDataChange(data: distributedData.ChangeInfo): void {

if (data.key === 'current_calculation') {
  const calculation = JSON.parse(data.value);
  EventBus.emit('calculationUpdated', calculation);

else if (data.key === ‘calculation_history’) {

  const history = JSON.parse(data.value);
  EventBus.emit('historyUpdated', history);

}

export const distCalcService = DistributedCalculationService.getInstance();

主界面与手写画布

// MathCalculator.ets
@Entry
@Component
struct MathCalculator {
@State strokes: handwriting.Stroke[] = [];
@State recognizedFormula: string = ‘’;
@State calculationResult: string = ‘’;
@State history: CalculationRecord[] = [];
@State connectedDevices: DeviceInfo[] = [];

aboutToAppear() {
this.setupListeners();
distCalcService.init();
build() {

Column() {
  // 手写画布
  HandwritingCanvas({
    strokes: this.strokes,
    onStrokeEnd: (stroke) => this.handleStroke(stroke)
  })
  .height('40%')
  .border({ width: 1, color: '#D9D9D9' })
  
  // 识别结果显示
  FormulaDisplay({
    formula: this.recognizedFormula,
    result: this.calculationResult
  })
  
  // 历史记录
  CalculationHistory({
    items: this.history,
    onSelect: (item) => this.selectHistory(item)
  })
  
  // 控制按钮
  ControlButtons({
    onClear: () => this.clear(),
    onCalculate: () => this.calculate(),
    onUndo: () => this.undo()
  })

.padding(20)

private setupListeners(): void {

EventBus.on('calculationUpdated', (calculation: CalculationRecord) => {
  if (calculation.deviceId !== deviceInfo.deviceId) {
    this.recognizedFormula = calculation.formula;
    this.calculationResult = calculation.result;

});

EventBus.on('historyUpdated', (history: CalculationRecord[]) => {
  this.history = history;
});

private async handleStroke(stroke: handwriting.Stroke): Promise<void> {

this.strokes.push(stroke);

// 实时识别
const [recognized] = await hwRecognitionService.recognize(this.strokes);
this.recognizedFormula = recognized;

// 同步当前输入
await distCalcService.syncCalculation({
  formula: this.recognizedFormula,
  result: this.calculationResult,
  deviceId: deviceInfo.deviceId,
  timestamp: Date.now()
});

private async calculate(): Promise<void> {

if (!this.recognizedFormula) return;

const result = mathEngine.evaluate(this.recognizedFormula);
this.calculationResult = typeof result === 'number' 

mathEngine.formatResult(result)

result;

// 保存到历史记录
const record: CalculationRecord = {
  formula: this.recognizedFormula,
  result: this.calculationResult,
  timestamp: Date.now(),
  device: deviceInfo.deviceName
};

this.history.unshift(record);
if (this.history.length > 100) {
  this.history.pop();

// 同步历史记录

await distCalcService.syncHistory(this.history);

private clear(): void {

this.strokes = [];
this.recognizedFormula = '';
this.calculationResult = '';

private undo(): void {

if (this.strokes.length > 0) {
  this.strokes.pop();

}

private selectHistory(item: CalculationRecord): void {
this.recognizedFormula = item.formula;
this.calculationResult = item.result;
}

三、关键功能说明
手写识别流程

sequenceDiagram
participant User
participant Canvas as 手写画布
participant Recognition as 识别服务
participant Calculation as 计算引擎

User->>Canvas: 手写数学公式
Canvas->>Recognition: 发送笔画数据
Recognition->>Recognition: 识别数学符号
Recognition->>Calculation: 返回标准表达式
Calculation->>Calculation: 安全计算
Calculation->>Canvas: 返回计算结果

数学符号识别表

手写符号 识别结果 数学含义

∫ \int 积分
∑ \sum 求和
√ \sqrt 平方根
∠ \angle 角度
∞ \infty 无穷大

分布式同步策略

数据类型 同步频率 数据量 同步方式

当前公式 实时同步 小 增量同步
计算结果 计算完成时 小 即时推送
历史记录 每小时同步 中 批量同步

四、项目扩展与优化
高级数学功能

// AdvancedMathSupport.ets
class AdvancedMathSupport {
private static matrixOperations(expr: string): string {
// 矩阵运算支持
return expr.replace(/[[(.*?)]]/g, ‘matrix($1)’);
private static calculusOperations(expr: string): string {

// 微积分支持
return expr.replace(/∫\((.*?)\)dx/g, 'integral($1)');

public static preprocess(expr: string): string {

return this.calculusOperations(this.matrixOperations(expr));

}

笔迹美化算法

// StrokeSmoothing.ets
class StrokeSmoothing {
public static smooth(strokes: handwriting.Stroke[]): handwriting.Stroke[] {
return strokes.map(stroke => {
const points = stroke.points;
if (points.length < 3) return stroke;

  const smoothed = [];
  for (let i = 1; i < points.length - 1; i++) {
    smoothed.push({
      x: (points[i-1].x + points[i].x + points[i+1].x) / 3,
      y: (points[i-1].y + points[i].y + points[i+1].y) / 3
    });

return { …stroke, points: smoothed };

});

}

协作编辑功能

// CollaborationService.ets
class CollaborationService {
private cursorPositions: Record<string, {x: number, y: number}> = {};

public updateCursor(deviceId: string, position: {x: number, y: number}): void {
this.cursorPositions[deviceId] = position;
EventBus.emit(‘cursorsUpdated’, this.cursorPositions);
public getCollaborators(): string[] {

return Object.keys(this.cursorPositions);

}

五、总结

本手写数学公式计算器实现了以下核心价值:
自然交互:通过手写输入数学公式

精准识别:专业数学符号识别引擎

实时计算:即时显示计算结果

多端协作:多人协同编辑公式

历史追溯:完整记录计算过程

扩展方向:
增加图形计算功能

开发公式导出为LaTeX

实现OCR识别打印公式

构建数学题库系统

注意事项:
需要申请ohos.permission.USE_HANDWRITING权限

复杂公式识别准确率依赖模型训练

分布式功能需设备在同一局域网

生产环境需添加更多错误处理

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐