写在前面
这是一段用C++与EasyX图形库绘制的充满童趣与艺术感的图像程序。它描绘了一棵枝繁叶茂的“花树”,树上盛开着七彩的花朵,树下系着一个别致的领结。整体画面色彩鲜艳、构图巧妙,仿佛是从童话故事中走出的一幕。本文将从技术需求、代码结构、创作流程等角度,深入解析这段程序的实现过程与设计思想。
系列文章
技术需求
-
图形库支持:程序依赖EasyX图形库,用于创建图形窗口、绘制线条和设置颜色。通过
initgraph
初始化窗口,并使用line
和setcolor
等函数完成基本图形绘制。 -
数学建模能力:花朵和领结的绘制基于极坐标方程,通过三角函数(如
sin
、cos
)和循环迭代,模拟花瓣和领结的曲线轮廓,体现数学与艺术的结合。 -
模块化设计:将不同元素(花朵、领结、树枝)封装为独立函数,提高代码复用性与可维护性。例如,
drawFlower
函数支持自定义花瓣数量与大小,增强灵活性。 -
色彩管理:通过
RGB
宏定义颜色值,精确控制每种花朵的色彩,实现彩虹般的视觉效果。领结采用白色,与彩色花朵形成对比,突出主体。 -
坐标系统运用:所有图形元素均基于像素坐标系定位,通过手动计算和精确绘图,构建出层次分明、结构合理的画面布局。
-
参数化设计:函数支持传入坐标、颜色、尺寸等参数,便于调整图形位置与样式,增强程序的可扩展性与适应性。
主要代码
创作不易,订阅后可查看完整代码
#include <iostream>
#include <graphics.h>
#include <cmath>
// 图形窗口尺寸和圆周率常量
const int WIDTH = 640;
const int HEIGHT = 480;
const double PI = 3.14159265;
// 绘制花朵的函数
void drawFlower(int x, int y, COLORREF color, int petalCount = 5, double petalSize = 15.0) {
int x1, y1, x2, y2;
double e;
setcolor(color);
for (double a = 0; a < 2 * PI; a += PI / 360) {
e = petalSize * (1 + sin(a * petalCount));
x1 = static_cast<int>(x + e * cos(a));
y1 = static_cast<int>(y + e * sin(a));
x2 = static_cast<int>(x + e * cos(a + PI / petalCount));
y2 = static_cast<int>(y + e * sin(a + PI / petalCount));
line(x1, y1, x2, y2);
}
}
// 绘制领结的函数
void drawTie(int x, int y, COLORREF color, double size = 80.0) {
int x1, y1, x2, y2;
double e;
setcolor(color);
for (double a = 0; a < 2 * PI; a += PI / 360) {
e = size * (1 + sin(a * 4));
x1 = static_cast<int>(x + e * cos(a));
y1 = static_cast<int>(y + e * sin(a) / 2);
x2 = static_cast<int>(x + e * cos(a + PI / 9));
y2 = static_cast<int>(y + e * sin(a + PI / 9) / 4.5);
line(x1, y1, x2, y2);
}
}
// 绘制树枝的函数
void drawBranches() {
setcolor(GREEN);
line(189, 372, 180, 400);
line(310, 160, 325, 68);
line(310, 160, 187, 374);
line(150, 140, 189, 374);
line(430, 176, 190, 374);
line(370, 110, 187, 374);
line(250, 72, 189, 372);
line(253, 192, 190, 374);
line(189, 372, 187, 400);
line(189, 372, 182, 400);
line(189, 372, 200, 120);
}
// 主函数
int main() {
initgraph(WIDTH, HEIGHT);
// 绘制树枝
drawBranches();
// 绘制花朵
drawFlower(320, 160, RGB(0xFF, 0x00, 0x00)); // 红色 #FF0000
drawFlower(200, 120, RGB(0xFF, 0x7F, 0x00)); // 橙色 #FF7F00
drawFlower(150, 140, RGB(0xFF, 0xFF, 0x00)); // 黄色 #FFFF00
drawFlower(430, 176, RGB(0x00, 0xFF, 0x00)); // 绿色 #00FF00
drawFlower(370, 110, RGB(0x00, 0xFF, 0xFF)); // 青色 #00FFFF
drawFlower(250, 72, RGB(0x00, 0x00, 0xFF)); // 蓝色 #0000FF
drawFlower(325, 68, RGB(0x8B, 0x00, 0xFF)); // 紫色 #8B00FF
drawFlower(253, 190, RGB(0xFF, 0xC0, 0xCB)); // 粉色 #FFC0CB
// 绘制领结
drawTie(195, 354, WHITE);
getchar();
closegraph();
return 0;
}
……
创作流程
在创作这段代码时,我的初衷是绘制一幅充满童趣与艺术感的图像,它不仅要色彩丰富,还要结构清晰,能够通过程序语言表达出一种“手工绘制”的温暖感。于是,我决定以“花树”为主题,将花朵、树枝和装饰元素(领结)有机组合,构建出一幅完整的画面。
首先,我规划了整体的构图布局。画面中心是一棵由多条直线构成的“花树”,树枝从主干分叉延伸,形成自然的分布。我通过手动计算关键点的坐标,用line
函数将它们连接起来。这些线条构成了画面的骨架,也为后续花朵的点缀提供了支撑点。
接下来,我设计了花朵的绘制逻辑。我希望花朵不是简单的圆形,而是具有花瓣层次感的图形。于是,我采用了极坐标方程,通过sin
函数调节花瓣的轮廓变化。在循环中,我根据角度a
计算出花瓣边缘的坐标,并用line
连接相邻点,形成连续的曲线。为了增强多样性,我还为drawFlower
函数添加了花瓣数量和大小的参数,使得每朵花都可以拥有独特的形态。
颜色的选择也至关重要。我为每朵花指定了不同的RGB值,从红色到紫色,覆盖了彩虹的全部色调。这种色彩的渐变不仅增强了视觉冲击力,也让整幅画面显得更加生动活泼。
在画面底部,我添加了一个领结元素,作为点缀。它的形状类似于一个对称的蝴蝶结,通过调整极坐标方程中的参数,使其呈现出独特的轮廓。我将它绘制在树枝的交汇处,仿佛是为这棵树系上的装饰,增添了几分俏皮感。
最后,我将所有元素整合到main
函数中,按照从下到上、从主干到装饰的顺序依次绘制。通过模块化的函数调用,代码结构清晰,易于维护和扩展。整个创作过程充满了探索与尝试,每一步都像是在用代码“作画”,将心中的图像一点点具象化。
写在后面
我是一只有趣的兔子,感谢你的喜欢!