可视化方程解析器
dongzhenmao · · 科技·工程
我或许应该发在这个区,没什么用,挺好玩的?
设一个多项式
你可以调整系数与多项式次数。直接拖动即可,毕竟这是复平面。
预编译:蓝奏云。
密码:67dg。
演示:
code
使用 ege 实现(编译记得开 release)。
#define SHOW_CONSOLE
#include <graphics.h>
#include <iostream>
#include <complex>
#include <cmath>
#include <thread>
#include <mutex>
#include <atomic>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <cstdio>
using std::cin;
using std::vector;
using std::string;
using std::complex;
using std::mutex;
using std::lock_guard;
const int width = 1280;
const int height = 1280;
const double math_pi = 3.14159265358979323846;
const double x_min = -5.0, x_max = 5.0;
const double y_min = -5.0, y_max = 5.0;
const double vanish_rate = 0.3;
std::vector<std::complex<double>> coeffs = {
{ -1.0, 0.0 },
{ 0.0, 0.0 },
{ 0.0, 0.0 },
{ 1.0, 0.0 }
};
std::mutex coeff_mutex;
std::atomic<bool> running(true);
std::atomic<bool> need_redraw(true);
int dragged_idx = -1;
std::complex<double> screen_to_complex(int sx, int sy) {
double rx = x_min + (x_max - x_min) * sx / width;
double ry = y_max - (y_max - y_min) * sy / height;
return std::complex<double>(rx, ry);
}
void complex_to_screen(std::complex<double> z, int &sx, int &sy) {
sx = (int)((z.real() - x_min) / (x_max - x_min) * width);
sy = (int)((y_max - z.imag()) / (y_max - y_min) * height);
}
std::complex<double> evaluate_polynomial(std::complex<double> z) {
if (coeffs.empty()) return 0.0;
std::complex<double> result = coeffs.back();
for (int i = (int)coeffs.size() - 2; i >= 0; --i) {
result = result * z + coeffs[i];
}
return result;
}
void console_input_thread() {
std::string line;
while (running) {
printf("\n==================================================\n");
printf(" [当前状态] 多项式次数 n = %d\n", (int)coeffs.size() - 1);
printf("表达式: f(z) = ");
for (int i = (int)coeffs.size() - 1; i >= 0; --i) {
printf("(%g + %gi)", coeffs[i].real(), coeffs[i].imag());
if (i > 0) printf("*z^%d + ", i);
}
printf("\n--------------------------------------------------\n");
printf(" [可用指令示例]: \n");
printf(" 1. 设置次数: n = 4 (新高次项系数默认为 1) \n");
printf(" 2. 设置系数: a0 = 1.5 -2.0 或 a2 = 1.0\n");
printf("--------------------------------------------------\n");
printf("请输入指令: ");
if (!std::getline(cin, line)) break;
for (char &ch : line) {
if (ch == '=') ch = ' ';
}
std::stringstream ss(line);
std::string token;
if (!(ss >> token)) continue;
if (token == "n") {
int new_n;
if (ss >> new_n) {
if (new_n >= 0 && new_n <= 30) {
std::lock_guard<std::mutex> lock(coeff_mutex);
dragged_idx = -1;
int old_size = coeffs.size();
int new_size = new_n + 1;
coeffs.resize(new_size);
if (new_size > old_size) {
for (int i = old_size; i < new_size; ++i) {
coeffs[i] = { 1.0, 0.0 };
}
}
need_redraw = true;
printf(">> 成功: 方程次数已更新为 %d\n", new_n);
} else {
printf(">> 错误: 次数限制在 0 到 30 之间. \n");
}
} else {
printf(">> 错误: 格式不正确, 请输入类似 n = 4\n");
}
}
else if (token[0] == 'a') {
try {
int idx = std::stoi(token.substr(1));
double re = 0.0, im = 0.0;
if (ss >> re) {
if (!(ss >> im)) {
im = 0.0;
}
std::lock_guard<std::mutex> lock(coeff_mutex);
if (idx >= 0 && idx < (int)coeffs.size()) {
coeffs[idx] = { re, im };
need_redraw = true;
printf(">> 成功: a%d 已更新为 %g + %gi\n", idx, re, im);
} else {
printf(">> 错误: 系数 a%d 越界, 当前最大可用系数为 a%d\n", idx, (int)coeffs.size() - 1);
}
} else {
printf(">> 错误: 未检测到有效的实部数值. \n");
}
}
catch (...) {
printf(">> 错误: 无法解析系数指令, 请检查格式. \n");
}
}
else {
printf(">> 错误: 无法识别的指令. \n");
}
}
}
int main() {
initgraph(width, height, INIT_RENDERMANUAL);
setcaption("交互式多项式可视化 (单调变暗+动态次数) ");
std::thread console_thread(console_input_thread);
console_thread.detach();
color_t *buffer = getbuffer((PIMAGE)NULL);
while (is_run()) {
while (mousemsg()) {
mouse_msg msg = getmouse();
std::complex<double> mouse_z = screen_to_complex(msg.x, msg.y);
if (msg.is_down() && msg.is_left()) {
std::lock_guard<std::mutex> lock(coeff_mutex);
for (int i = 0; i < (int)coeffs.size(); ++i) {
if (abs(coeffs[i] - mouse_z) < 0.15) {
dragged_idx = i;
break;
}
}
}
else if (msg.is_up() && msg.is_left()) {
dragged_idx = -1;
}
else if (msg.is_move() && dragged_idx != -1) {
std::lock_guard<std::mutex> lock(coeff_mutex);
coeffs[dragged_idx] = mouse_z;
need_redraw = true;
}
}
if (need_redraw) {
std::lock_guard<std::mutex> lock(coeff_mutex);
for (int py = 0; py < height; ++py) {
for (int px = 0; px < width; ++px) {
std::complex<double> z = screen_to_complex(px, py);
std::complex<double> w = evaluate_polynomial(z);
double r = abs(w);
double theta = arg(w);
float h = (float)((theta + math_pi) / (2.0 * math_pi) * 360.0);
if (h >= 360.0f) h = 0.0f;
float s = (float)(1.0 - 1.0 / (1.0 + r * r * 80.0));
float v = (float)(1.0 / (1.0 + vanish_rate * r));
if (s < 0.0f) s = 0.0f; if (s > 1.0f) s = 1.0f;
if (v < 0.0f) v = 0.0f; if (v > 1.0f) v = 1.0f;
buffer[py * width + px] = hsv2rgb(h, s, v);
}
}
for (int i = 0; i < (int)coeffs.size(); ++i) {
int sx, sy;
complex_to_screen(coeffs[i], sx, sy);
setfillcolor(EGERGB(255, 255, 255));
setcolor(EGERGB(0, 0, 0));
fillcircle(sx, sy, 6);
setcolor(EGERGB(255, 255, 255));
char label[8];
sprintf(label, "a%d", i);
outtextxy(sx + 8, sy - 8, label);
}
need_redraw = false;
}
delay_fps(60);
}
running = false;
closegraph();
return 0;
}