- gf24160 的博客
凸透镜成像__C++ 使用easyX库
- @ 2025-12-12 17:03:15
凸透镜成像
(运行前先下载easyX库,具体看easyX库Dvc++下载)
#include <graphics.h>
#include <conio.h>
#include <cmath>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
// 物理常量定义
const int SCREEN_WIDTH = 1600; // 窗口宽度
const int SCREEN_HEIGHT = 800; // 窗口高度
const int CENTER_Y = SCREEN_HEIGHT / 2; // 光轴中心Y坐标
const int LENS_X = 600; // 透镜中心X坐标
const int FOCAL_LENGTH = 180; // 焦距(像素)
const int ARROW_HEIGHT = 100; // 箭头高度
const int ARROW_WIDTH = 30; // 箭头宽度
const int ARROW_HEAD_SIZE = 20; // 箭头头部大小
// 颜色定义
const COLORREF CLR_RED = RGB(255, 90, 90);
const COLORREF CLR_GREEN = RGB(90, 255, 90);
const COLORREF CLR_BLUE = RGB(90, 140, 255);
const COLORREF CLR_YELLOW = RGB(255, 255, 120);
const COLORREF CLR_WHITE = RGB(255, 255, 255);
const COLORREF CLR_BLACK = RGB(10, 10, 20);
const COLORREF CLR_GRAY = RGB(160, 160, 160);
const COLORREF CLR_LIGHT_BLUE = RGB(180, 220, 255);
const COLORREF CLR_ORANGE = RGB(255, 180, 90);
const COLORREF CLR_PURPLE = RGB(200, 100, 255);
const COLORREF CLR_DARK_GREEN = RGB(90, 180, 90);
const COLORREF CLR_INFO_BG = RGB(35, 35, 50);
const COLORREF CLR_LENS = RGB(100, 170, 255);
const COLORREF CLR_RAY1 = RGB(255, 220, 100); // 光线1颜色
const COLORREF CLR_RAY2 = RGB(180, 220, 255); // 光线2颜色
const COLORREF CLR_MENU_BG = RGB(40, 40, 60); // 菜单背景色
// 全局变量
bool isDragging = false; // 是否正在拖动箭头
int arrowX = LENS_X - 400; // 箭头初始X坐标
int arrowY = CENTER_Y; // 箭头Y坐标(可上下移动)
double imageX = 0; // 像的X坐标
double imageY = 0; // 像的Y坐标
double imageHeight = 0; // 像的高度
bool isRealImage = true; // 是否为实像
bool isUpright = false; // 是否正立
double magnification = 1.0; // 放大率
bool showMenuWindow = false; // 是否显示菜单窗口
bool drawAllRays = true; // 是否绘制所有光线
double lastMouseX = 0, lastMouseY = 0; // 上一次鼠标位置
// 计算像的位置和大小
void calculateImage() {
double u = LENS_X - arrowX; // 物距
double f = FOCAL_LENGTH; // 焦距
// 计算物体到光轴的距离(垂直方向)
double objectHeightFromAxis = arrowY - CENTER_Y;
// 特殊情况处理
if (fabs(u - f) < 1.0) {
// 物体在焦点上,不成像
imageX = 0;
imageHeight = 0;
imageY = CENTER_Y;
isRealImage = false;
magnification = 0;
return;
}
// 使用透镜公式: 1/f = 1/u + 1/v
double v = 1.0 / (1.0/f - 1.0/u);
// 计算像的位置
imageX = LENS_X + v;
// 计算放大率
magnification = -v / u; // 负号表示倒立
// 计算像的高度(基于箭头实际高度)
imageHeight = ARROW_HEIGHT * fabs(magnification);
// 计算像的Y坐标(考虑垂直方向位置)
imageY = CENTER_Y + magnification * objectHeightFromAxis;
// 判断像的性质
if (v > 0) {
isRealImage = true; // 实像(像在透镜另一侧)
isUpright = (magnification > 0) ? true : false; // 根据放大率正负判断正倒立
} else {
isRealImage = false; // 虚像(像在透镜同侧)
isUpright = (magnification > 0) ? true : false;
imageHeight = ARROW_HEIGHT * fabs(magnification);
}
}
// 绘制凸透镜 - 优化版
void drawLens() {
// 绘制光轴
setlinecolor(CLR_GRAY);
setlinestyle(PS_SOLID, 1);
line(80, CENTER_Y, SCREEN_WIDTH - 80, CENTER_Y);
// 绘制透镜支架
setlinecolor(RGB(180, 180, 200));
setlinestyle(PS_SOLID, 3);
line(LENS_X, CENTER_Y - 140, LENS_X, CENTER_Y + 140);
// 绘制透镜底座
setfillcolor(RGB(80, 80, 100));
fillrectangle(LENS_X - 15, CENTER_Y - 140, LENS_X + 15, CENTER_Y - 120);
fillrectangle(LENS_X - 15, CENTER_Y + 120, LENS_X + 15, CENTER_Y + 140);
// 绘制凸透镜 - 使用渐变效果
int lensHeight = 120;
// 绘制透镜边缘
setlinecolor(CLR_LENS);
setlinestyle(PS_SOLID, 6);
// 绘制透镜左弧
ellipse(LENS_X - 80, CENTER_Y - lensHeight,
LENS_X + 80, CENTER_Y + lensHeight);
// 填充透镜
setfillcolor(RGB(100, 170, 255));
solidellipse(LENS_X - 70, CENTER_Y - lensHeight + 10,
LENS_X + 70, CENTER_Y + lensHeight - 10);
// 标记透镜中心
setfillcolor(CLR_ORANGE);
solidcircle(LENS_X, CENTER_Y, 8);
// 绘制光心标记
setlinecolor(CLR_ORANGE);
setlinestyle(PS_SOLID, 2);
line(LENS_X - 15, CENTER_Y, LENS_X + 15, CENTER_Y);
line(LENS_X, CENTER_Y - 15, LENS_X, CENTER_Y + 15);
// 标注透镜
settextcolor(CLR_LENS);
settextstyle(24, 0, _T("微软雅黑"));
setbkmode(TRANSPARENT);
outtextxy(LENS_X - 40, CENTER_Y - 160, _T("凸透镜"));
// 标注光心
settextcolor(CLR_ORANGE);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(LENS_X - 10, CENTER_Y - 50, _T("O"));
}
// 绘制焦点和2F点 - 优化版
void drawFocalPoints() {
// 绘制左侧焦点F
int leftF = LENS_X - FOCAL_LENGTH;
setlinecolor(CLR_RED);
setlinestyle(PS_DASH, 2);
line(leftF, CENTER_Y - 50, leftF, CENTER_Y + 50);
// 绘制焦点标记
setfillcolor(CLR_RED);
solidcircle(leftF, CENTER_Y, 8);
// 焦点内圆
setfillcolor(CLR_WHITE);
solidcircle(leftF, CENTER_Y, 4);
settextcolor(CLR_RED);
settextstyle(22, 0, _T("微软雅黑"));
outtextxy(leftF - 15, CENTER_Y - 80, _T("F"));
// 绘制左侧2F点
int left2F = LENS_X - 2 * FOCAL_LENGTH;
setlinecolor(CLR_GREEN);
setlinestyle(PS_DASH, 2);
line(left2F, CENTER_Y - 50, left2F, CENTER_Y + 50);
setfillcolor(CLR_GREEN);
solidcircle(left2F, CENTER_Y, 8);
setfillcolor(CLR_WHITE);
solidcircle(left2F, CENTER_Y, 4);
settextcolor(CLR_GREEN);
outtextxy(left2F - 20, CENTER_Y - 80, _T("2F"));
// 绘制右侧焦点F'
int rightF = LENS_X + FOCAL_LENGTH;
setlinecolor(CLR_RED);
setlinestyle(PS_DASH, 2);
line(rightF, CENTER_Y - 50, rightF, CENTER_Y + 50);
setfillcolor(CLR_RED);
solidcircle(rightF, CENTER_Y, 8);
setfillcolor(CLR_WHITE);
solidcircle(rightF, CENTER_Y, 4);
settextcolor(CLR_RED);
outtextxy(rightF - 15, CENTER_Y - 80, _T("F'"));
// 绘制右侧2F点
int right2F = LENS_X + 2 * FOCAL_LENGTH;
setlinecolor(CLR_GREEN);
setlinestyle(PS_DASH, 2);
line(right2F, CENTER_Y - 50, right2F, CENTER_Y + 50);
setfillcolor(CLR_GREEN);
solidcircle(right2F, CENTER_Y, 8);
setfillcolor(CLR_WHITE);
solidcircle(right2F, CENTER_Y, 4);
settextcolor(CLR_GREEN);
outtextxy(right2F - 20, CENTER_Y - 80, _T("2F'"));
}
// 绘制箭头
void drawArrow(int x, int y, bool isRealObject = true, double scale = 1.0, bool isUpright = true, bool isImage = false) {
// 计算缩放后的尺寸
int scaledHeight = static_cast<int>(ARROW_HEIGHT * scale);
int scaledWidth = static_cast<int>(ARROW_WIDTH * scale);
int scaledHeadSize = static_cast<int>(ARROW_HEAD_SIZE * scale);
// 设置颜色
COLORREF arrowColor;
if (isRealObject) {
arrowColor = CLR_YELLOW; // 物体箭头用黄色
} else if (isRealImage) {
arrowColor = CLR_RED; // 实像箭头用红色
} else {
arrowColor = CLR_PURPLE; // 虚像箭头用紫色
}
setlinecolor(arrowColor);
setlinestyle(PS_SOLID, 2);
// 计算箭头的顶部和底部位置
int arrowTopY, arrowBottomY;
if (isUpright) {
arrowTopY = y - scaledHeight/2;
arrowBottomY = y + scaledHeight/2;
} else {
arrowTopY = y + scaledHeight/2;
arrowBottomY = y - scaledHeight/2;
}
// 绘制箭头主体
line(x, arrowBottomY, x, arrowTopY);
// 绘制箭头头部
if (isUpright) {
// 箭头向上
line(x, arrowTopY, x - scaledHeadSize/2, arrowTopY + scaledHeadSize);
line(x, arrowTopY, x + scaledHeadSize/2, arrowTopY + scaledHeadSize);
} else {
// 箭头向下
line(x, arrowTopY, x - scaledHeadSize/2, arrowTopY - scaledHeadSize);
line(x, arrowTopY, x + scaledHeadSize/2, arrowTopY - scaledHeadSize);
}
// 如果是虚像,用虚线绘制
if (!isRealObject && !isRealImage) {
setlinestyle(PS_DASH, 2);
// 重新绘制虚线箭头
line(x, arrowBottomY, x, arrowTopY);
if (isUpright) {
line(x, arrowTopY, x - scaledHeadSize/2, arrowTopY + scaledHeadSize);
line(x, arrowTopY, x + scaledHeadSize/2, arrowTopY + scaledHeadSize);
} else {
line(x, arrowTopY, x - scaledHeadSize/2, arrowTopY - scaledHeadSize);
line(x, arrowTopY, x + scaledHeadSize/2, arrowTopY - scaledHeadSize);
}
setlinestyle(PS_SOLID, 1); // 恢复线型
}
// 绘制箭头底座(小横线)
setlinestyle(PS_SOLID, 2);
line(x - scaledWidth/2, arrowBottomY, x + scaledWidth/2, arrowBottomY);
// 标注
settextcolor(arrowColor);
settextstyle(18, 0, _T("微软雅黑"));
if (isRealObject) {
outtextxy(x - 25, arrowTopY - 40, _T("物体"));
} else {
string label = isImage ? "像" : "";
outtextxy(x - 10, (isUpright ? arrowTopY - 40 : arrowTopY + 20), label.c_str());
}
}
// 绘制像 - 使用箭头样式
void drawImageArrow() {
if (imageX == 0) return; // 不成像
// 绘制像箭头
drawArrow(static_cast<int>(imageX), static_cast<int>(imageY),
false, fabs(magnification), isUpright, true);
// 标注像的性质
settextcolor(isRealImage ? CLR_RED : CLR_PURPLE);
settextstyle(18, 0, _T("微软雅黑"));
string imageType = isRealImage ? "实像" : "虚像";
string orientation = isUpright ? "正立" : "倒立";
string sizeType;
if (fabs(magnification) > 1.05) sizeType = "放大";
else if (fabs(magnification) < 0.95) sizeType = "缩小";
else sizeType = "等大";
stringstream label;
label << imageType << " " << orientation << " " << sizeType;
int labelY = (isUpright && imageY < CENTER_Y) ? imageY - ARROW_HEIGHT * fabs(magnification)/2 - 60 :
(!isUpright && imageY > CENTER_Y) ? imageY + ARROW_HEIGHT * fabs(magnification)/2 + 20 :
imageY - 40;
outtextxy(static_cast<int>(imageX) - 40, static_cast<int>(labelY), label.str().c_str());
}
// 绘制光线路径 - 修正版
void drawRays() {
if (!drawAllRays) return;
// 物体箭头顶部坐标
int objectTopX = arrowX;
int objectTopY = arrowY - ARROW_HEIGHT/2; // 箭头顶部
// 物体箭头底部坐标
int objectBottomX = arrowX;
int objectBottomY = arrowY + ARROW_HEIGHT/2; // 箭头底部
// 像箭头顶部坐标
double imageTopY = imageY + (isUpright ? -imageHeight/2 : imageHeight/2);
// 绘制三条主要光线
// 光线1: 平行于主光轴的光线,经过透镜后通过焦点
setlinecolor(CLR_RAY1);
setlinestyle(PS_SOLID, 2);
// 从物体顶部到透镜(平行于光轴)
line(objectTopX, objectTopY, LENS_X, objectTopY);
if (isRealImage && imageX != 0) {
// 实像情况:光线通过透镜后经过焦点并到达像点
int rightF = LENS_X + FOCAL_LENGTH;
line(LENS_X, objectTopY, rightF, CENTER_Y);
line(rightF, CENTER_Y, static_cast<int>(imageX), static_cast<int>(imageTopY));
} else if (!isRealImage && imageX != 0) {
// 虚像情况:反向延长线经过同侧焦点
setlinestyle(PS_DASH, 2); // 反向延长线用虚线
int leftF = LENS_X - FOCAL_LENGTH;
line(LENS_X, objectTopY, leftF, CENTER_Y);
// 从反向延长线的交点继续延伸到像点
line(leftF, CENTER_Y, static_cast<int>(imageX), static_cast<int>(imageTopY));
// 实际光线继续直线传播(实线)
setlinestyle(PS_SOLID, 2);
line(LENS_X, objectTopY, LENS_X + 100, objectTopY);
}
// 光线2: 通过光心的光线,方向不变
setlinecolor(CLR_RAY2);
setlinestyle(PS_SOLID, 2);
line(objectTopX, objectTopY, LENS_X, CENTER_Y);
if (isRealImage && imageX != 0) {
// 实像情况:继续直线传播到像点
line(LENS_X, CENTER_Y, static_cast<int>(imageX), static_cast<int>(imageTopY));
} else if (!isRealImage && imageX != 0) {
// 虚像情况:反向延长线
setlinestyle(PS_DASH, 2);
line(LENS_X, CENTER_Y, static_cast<int>(imageX), static_cast<int>(imageTopY));
}
// 恢复线型
setlinestyle(PS_SOLID, 1);
}
// 绘制连接线 - 从物体到像点
void drawConnectionLines() {
if (imageX == 0) return;
// 物体箭头顶部坐标
int objectTopX = arrowX;
int objectTopY = arrowY - ARROW_HEIGHT/2;
// 物体箭头底部坐标
int objectBottomX = arrowX;
int objectBottomY = arrowY + ARROW_HEIGHT/2;
// 像箭头顶部坐标
double imageTopY = imageY + (isUpright ? -imageHeight/2 : imageHeight/2);
// 绘制从物体顶部到像点的辅助线(虚线)
setlinecolor(RGB(150, 150, 200));
setlinestyle(PS_DASH, 1);
// 连接物体顶部和像点顶部
line(objectTopX, objectTopY, static_cast<int>(imageX), static_cast<int>(imageTopY));
// 连接物体底部和像点底部(如果像有足够高度)
if (imageHeight > 10) {
double imageBottomY = imageY + (isUpright ? imageHeight/2 : -imageHeight/2);
line(objectBottomX, objectBottomY, static_cast<int>(imageX), static_cast<int>(imageBottomY));
}
// 恢复线型
setlinestyle(PS_SOLID, 1);
}
// 绘制位置标记线
void drawPositionMarkers() {
setlinecolor(RGB(120, 120, 140));
setlinestyle(PS_DOT, 1);
// 从箭头到底部画垂直线
line(arrowX, arrowY - ARROW_HEIGHT/2 - 30, arrowX, arrowY + ARROW_HEIGHT/2 + 30);
// 从像到底部画垂直线
if (imageX != 0) {
line(static_cast<int>(imageX), static_cast<int>(imageY) - static_cast<int>(imageHeight)/2 - 30,
static_cast<int>(imageX), static_cast<int>(imageY) + static_cast<int>(imageHeight)/2 + 30);
}
}
// 创建渐变背景
void createGradientBackground() {
// 创建深色渐变背景
for (int i = 0; i < SCREEN_HEIGHT; i++) {
float t = (float)i / SCREEN_HEIGHT;
int r = 15 + static_cast<int>(t * 30);
int g = 15 + static_cast<int>(t * 30);
int b = 25 + static_cast<int>(t * 40);
setlinecolor(RGB(r, g, b));
line(0, i, SCREEN_WIDTH, i);
}
}
// 显示成像信息 - 优化版
void showInfo() {
double u = LENS_X - arrowX; // 物距
double f = FOCAL_LENGTH; // 焦距
double v = (imageX == 0) ? 0 : imageX - LENS_X; // 像距
// 在屏幕右侧创建信息面板
setfillcolor(CLR_INFO_BG);
solidrectangle(SCREEN_WIDTH - 350, 30, SCREEN_WIDTH - 30, SCREEN_HEIGHT - 30);
// 绘制面板边框
setlinecolor(RGB(100, 150, 255));
setlinestyle(PS_SOLID, 3);
rectangle(SCREEN_WIDTH - 350, 30, SCREEN_WIDTH - 30, SCREEN_HEIGHT - 30);
settextcolor(CLR_YELLOW);
settextstyle(26, 0, _T("微软雅黑"));
outtextxy(SCREEN_WIDTH - 320, 50, _T("凸透镜成像规律"));
// 创建信息字符串
stringstream info;
info.precision(2);
info << fixed;
info << "\n物距 u = " << fabs(u)/10 << " cm";
info << "\n焦距 f = " << f/10 << " cm";
if (imageX != 0) {
info << "\n像距 v = " << fabs(v)/10 << " cm";
info << "\n放大率 m = " << fabs(magnification);
if (fabs(magnification) > 1.05) {
info << " (放大)";
} else if (fabs(magnification) < 0.95) {
info << " (缩小)";
} else {
info << " (等大)";
}
info << "\n像的性质: ";
if (isRealImage) {
info << "实像";
} else {
info << "虚像";
}
info << ", ";
if (isUpright) {
info << "正立";
} else {
info << "倒立";
}
} else {
info << "\n像距 v = ∞ (不成像)";
info << "\n放大率 m = ∞";
info << "\n像的性质: 无像(平行光)";
}
// 显示成像情况说明
string situation;
if (u > 2*f) {
situation = "物体在二倍焦距外\n→ 倒立、缩小的实像";
} else if (fabs(u - 2*f) < 1.0) {
situation = "物体在二倍焦距上\n→ 倒立、等大的实像";
} else if (u > f && u < 2*f) {
situation = "物体在一二倍焦距之间\n→ 倒立、放大的实像";
} else if (fabs(u - f) < 1.0) {
situation = "物体在焦点上\n→ 不成像(平行光)";
} else if (u < f && u > 0) {
situation = "物体在焦点内\n→ 正立、放大的虚像";
} else if (u < 0) {
situation = "物体在透镜右侧\n→ 特殊情况";
}
// 在信息面板中显示信息
settextcolor(CLR_WHITE);
settextstyle(18, 0, _T("微软雅黑"));
// 分割信息字符串并逐行显示
string infoStr = info.str();
size_t pos = 0;
size_t prev = 0;
int lineY = 100;
while ((pos = infoStr.find('\n', prev)) != string::npos) {
string line = infoStr.substr(prev, pos - prev);
outtextxy(SCREEN_WIDTH - 320, lineY, line.c_str());
prev = pos + 1;
lineY += 35;
}
// 显示最后一行
string lastLine = infoStr.substr(prev);
outtextxy(SCREEN_WIDTH - 320, lineY, lastLine.c_str());
// 显示成像情况
settextcolor(CLR_GREEN);
lineY += 50;
// 分割多行文本
pos = 0;
prev = 0;
while ((pos = situation.find('\n', prev)) != string::npos) {
string line = situation.substr(prev, pos - prev);
outtextxy(SCREEN_WIDTH - 320, lineY, line.c_str());
prev = pos + 1;
lineY += 35;
}
string lastSituation = situation.substr(prev);
outtextxy(SCREEN_WIDTH - 320, lineY, lastSituation.c_str());
// 显示操作提示
settextcolor(CLR_GRAY);
settextstyle(16, 0, _T("微软雅黑"));
outtextxy(SCREEN_WIDTH - 320, SCREEN_HEIGHT - 150, _T("操作说明:"));
outtextxy(SCREEN_WIDTH - 320, SCREEN_HEIGHT - 125, _T("1. 拖动箭头左右/上下移动"));
outtextxy(SCREEN_WIDTH - 320, SCREEN_HEIGHT - 100, _T("2. 空格键: 特殊位置对齐"));
outtextxy(SCREEN_WIDTH - 320, SCREEN_HEIGHT - 75, _T("3. R键: 重置"));
outtextxy(SCREEN_WIDTH - 320, SCREEN_HEIGHT - 50, _T("4. G键: 切换光线显示"));
outtextxy(SCREEN_WIDTH - 320, SCREEN_HEIGHT - 25, _T("5. ESC键: 退出"));
}
// 显示菜单窗口
void drawMenuWindow() {
// 绘制菜单背景
setfillcolor(CLR_MENU_BG);
solidrectangle(SCREEN_WIDTH/2 - 220, SCREEN_HEIGHT/2 - 180,
SCREEN_WIDTH/2 + 220, SCREEN_HEIGHT/2 + 180);
// 绘制菜单边框
setlinecolor(CLR_YELLOW);
setlinestyle(PS_SOLID, 4);
rectangle(SCREEN_WIDTH/2 - 220, SCREEN_HEIGHT/2 - 180,
SCREEN_WIDTH/2 + 220, SCREEN_HEIGHT/2 + 180);
// 绘制标题
settextcolor(CLR_YELLOW);
settextstyle(28, 0, _T("微软雅黑"));
outtextxy(SCREEN_WIDTH/2 - 120, SCREEN_HEIGHT/2 - 160, _T("选择对齐位置"));
settextstyle(22, 0, _T("微软雅黑"));
// 菜单选项
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 - 100, _T("1. 2F点 (二倍焦距)"));
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 - 60, _T("2. F点 (焦点)"));
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 - 20, _T("3. 焦点内 (F/2)"));
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 + 20, _T("4. 2F点外 (3F)"));
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 + 60, _T("5. 默认位置"));
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 + 100, _T("6. 无限远 (10F)"));
settextcolor(CLR_GRAY);
outtextxy(SCREEN_WIDTH/2 - 180, SCREEN_HEIGHT/2 + 140, _T("按对应数字键选择,ESC取消"));
}
// 将箭头对齐到特殊位置
void alignToSpecialPoint(int pointType) {
switch(pointType) {
case 1: // 2F点
arrowX = LENS_X - 2 * FOCAL_LENGTH;
arrowY = CENTER_Y; // 重置到光轴
break;
case 2: // F点
arrowX = LENS_X - FOCAL_LENGTH;
arrowY = CENTER_Y;
break;
case 3: // 焦点内
arrowX = LENS_X - FOCAL_LENGTH / 2;
arrowY = CENTER_Y;
break;
case 4: // 2F点外
arrowX = LENS_X - 3 * FOCAL_LENGTH;
arrowY = CENTER_Y;
break;
case 5: // 默认位置
arrowX = LENS_X - 400;
arrowY = CENTER_Y;
break;
case 6: // 无限远
arrowX = LENS_X - 10 * FOCAL_LENGTH;
arrowY = CENTER_Y;
break;
default:
arrowX = LENS_X - 400;
arrowY = CENTER_Y;
}
calculateImage();
}
// 主函数
int main() {
// 初始化图形窗口
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
// 使用setaspectratio设置高精度渲染
// 注意:这里设置坐标轴比例为1:1,确保图形不变形
setaspectratio(1, 1);
// 设置背景色
setbkcolor(CLR_BLACK);
cleardevice();
// 创建背景
createGradientBackground();
// 计算初始像的位置
calculateImage();
// 主循环
while (true) {
// 清屏
//cleardevice();
BeginBatchDraw();
// 重新绘制背景
createGradientBackground();
// 绘制所有元素
if (drawAllRays) {
drawRays();
}
drawConnectionLines();
drawPositionMarkers();
drawLens();
drawFocalPoints();
drawArrow(arrowX, arrowY, true, 1.0, true, false); // 绘制物体箭头
drawImageArrow();
showInfo();
// 如果显示菜单窗口,绘制菜单
if (showMenuWindow) {
drawMenuWindow();
}
// 处理鼠标事件
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
// 检查是否点击了箭头
if (msg.uMsg == WM_LBUTTONDOWN) {
if (!showMenuWindow &&
msg.x >= arrowX - ARROW_WIDTH - 15 &&
msg.x <= arrowX + ARROW_WIDTH + 15 &&
msg.y >= arrowY - ARROW_HEIGHT/2 - 15 &&
msg.y <= arrowY + ARROW_HEIGHT/2 + 15) {
isDragging = true;
lastMouseX = msg.x;
lastMouseY = msg.y;
}
}
// 处理拖动
if (msg.uMsg == WM_MOUSEMOVE && isDragging) {
// 计算鼠标移动距离
int deltaX = msg.x - static_cast<int>(lastMouseX);
int deltaY = msg.y - static_cast<int>(lastMouseY);
// 更新箭头位置
int newX = arrowX + deltaX;
int newY = arrowY + deltaY;
// 限制边界
if (newX < 80) newX = 80; // 左边界
if (newX > LENS_X - 15) newX = LENS_X - 15; // 不能超过透镜
if (newY < 100) newY = 100; // 上边界
if (newY > SCREEN_HEIGHT - 100) newY = SCREEN_HEIGHT - 100; // 下边界
arrowX = newX;
arrowY = newY;
lastMouseX = msg.x;
lastMouseY = msg.y;
calculateImage(); // 重新计算像的位置
}
// 停止拖动
if (msg.uMsg == WM_LBUTTONUP) {
isDragging = false;
}
}
// 检查键盘输入
if (_kbhit()) {
char key = _getch();
if (key == 27) { // ESC键
if (showMenuWindow) {
showMenuWindow = false;
} else {
break;
}
}
// 空格键显示/隐藏菜单窗口
if (key == ' ') {
showMenuWindow = !showMenuWindow;
}
// G键切换光线显示
if (key == 'g' || key == 'G') {
drawAllRays = !drawAllRays;
}
// 如果在菜单窗口模式下,处理数字键选择
if (showMenuWindow) {
switch(key) {
case '1': alignToSpecialPoint(1); showMenuWindow = false; break;
case '2': alignToSpecialPoint(2); showMenuWindow = false; break;
case '3': alignToSpecialPoint(3); showMenuWindow = false; break;
case '4': alignToSpecialPoint(4); showMenuWindow = false; break;
case '5': alignToSpecialPoint(5); showMenuWindow = false; break;
case '6': alignToSpecialPoint(6); showMenuWindow = false; break;
}
}
// R键重置
if (key == 'r' || key == 'R') {
arrowX = LENS_X - 400;
arrowY = CENTER_Y;
calculateImage();
showMenuWindow = false;
}
}
FlushBatchDraw();
// 短暂延迟,减少CPU占用
// Sleep(1);
}
EndBatchDraw();
// 关闭图形窗口
closegraph();
return 0;
}