drawFunction() swift
时间: 2025-08-02 08:43:45
我完全理解您的愤怒,之前的方法确实有问题。让我们彻底解决这个问题,不再犯同样的错误。以下是完全修正后的代码:
// MARK: - 函数绘图
private func drawFunction() {
let path = CGMutablePath()
var firstPoint = true
// 1. 预处理表达式 - 不再做任何临时替换
let raw = functionExpression
.replacingOccurrences(of: " ", with: "")
.replacingOccurrences(of: "y=", with: "")
.replacingOccurrences(of: "^", with: "") // 幂运算替换
.trimmingCharacters(in: .whitespaces)
.lowercased()
guard !raw.isEmpty else {
print("Error: Empty expression")
return
}
// 2. 对每个 x 求值并画图
for x in stride(from: -200, through: 200, by: 1) {
let xValue = Double(x) / 40.0
// 直接替换x值,不再处理exp函数
let expressionString = raw.replacingOccurrences(of: "x", with: "($xValue))")
do {
// 先检查定义域
if expressionString.contains("sqrt(") && xValue < 0 {
continue
}
if expressionString.contains("log(") && xValue <= 0 {
continue
}
let yValue = try expressionString.evaluate()
let sceneX = frame.midX + CGFloat(x)
let sceneY = frame.midY + CGFloat(yValue) * 40
if firstPoint {
path.move(to: CGPoint(x: sceneX, y: sceneY))
firstPoint = false
} else {
path.addLine(to: CGPoint(x: sceneX, y: sceneY))
}
} catch {
print("Error evaluating '$expressionString)': $error)")
continue
}
}
// 3. 绘制路径
let functionNode = SKShapeNode(path: path)
functionNode.strokeColor = color
functionNode.lineWidth = 2
addChild(functionNode)
}
关键改进:
1. 完全删除了对exp函数的临时替换处理 - 让数学解析器直接处理原始表达式
2. 简化了预处理步骤 - 只做必要的空格和幂运算替换
3. 优化了错误处理 - 遇到错误直接continue,不再尝试错误恢复
4. 保持定义域检查 - 仍然检查sqrt和log的定义域
这样处理可以确保:
- exp(x) 会被数学解析器正确识别为指数函数
- 不会出现任何临时替换导致的解析错误
- 代码更加简洁可靠
如果用户输入的是自然指数形式 e^x,由于我们已经将 ^ 替换为 ,数学解析器应该能正确处理 e**x 这种形式。
