#include <iostream>
#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
using namespace std;
void Drawcircle1(int x,int y,int r)//黄色实心圆
{
setlinecolor(BLACK);
circle(x, y, r);
setfillcolor(YELLOW);
fillcircle(x, y, r);
}
void Drawcircle2(int x, int y, int r)//随机颜色实心圆
{
float h = rand() % 360;
COLORREF color = HSVtoRGB(h, 0.6, 0.8);
setfillcolor(color);
fillcircle(x, y, r);
}
void Drawcircle3(int x, int y, int r)//随机颜色同心圆
{
while (r > 0)
{
float h = rand() % 360;
COLORREF color = HSVtoRGB(h, 0.6, 0.8);
setlinecolor(RGB(255, 255, 255));//白色描边
setfillcolor(color);
fillcircle(x, y, r);
r -= 5;//注意这个同心圆半径不能减少得太小,要不然颜色表现不出来
}
}
void Drawcircle4(int x, int y, int r)//随机颜色同心圆
{
while (r > 0)
{
float h = rand() % 360;
COLORREF color = HSVtoRGB(h, 0.6, 0.8);
setlinecolor(color);
circle(x, y, r);
r -= 5;//注意这个同心圆半径不能减少得太小,要不然颜色表现不出来
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char input; int DrawMode = 1;//有四种模式,先设定为第一种模式
while (1)
{
cout << "请你输入模式:" << endl;//在控制台提醒用户输入模式
cin >> input;//用户可输入1/2/3/4四种模式,如果用户输入其他数字,则不断让用户重新输入
if (input == '1')//因为input类型是char,所以是‘1’,不是1噢!
{
DrawMode = 1;
break;
}
else if (input == '2')
{
DrawMode = 2;
break;
}
else if (input == '3')
{
DrawMode = 3;
break;
}
else if (input == '4')
{
DrawMode = 4;
break;
}
else
cout << "无效输入,请重新输入" << endl;
}
int width, height;
width = 800; height = 600;
initgraph(width, height);
setbkcolor(WHITE);
cleardevice();
int xArray[200], yArray[200], rArray[200], circleNum, rmin, rmax;
circleNum = 1; rmin = 8; rmax = 60;
float dist2; int isOk = 1; float r2; int issmall;
int x, y, r;
x = rand() % width;
y = rand() % height;
r = rand() % (rmax - rmin + 1) + rmin;//随机生成一个圆的数值,这个r的范围是8-50
xArray[0] = x;//
yArray[0] = y;
rArray[0] = r;
setlinecolor(BLACK);
circle(xArray[circleNum], yArray[circleNum], rArray[circleNum]);
setfillcolor(YELLOW);
fillcircle(xArray[circleNum], yArray[circleNum], rArray[circleNum]);//先随便设置一个圆放入数组中并画出来
while (circleNum < 200)//循环直至数组中放满200个圆
{
int x, y, r;
x = rand() % width;//是x不是xArray[i],先是尝试生成三个数值,满足不相交条件里再放进数组里
y = rand() % height;
r = rand() % (rmax - rmin + 1) + rmin;//随机生成一个圆的数值
for (int i = 0; i < circleNum; i++)//判断数组中的圆与新增的圆是否相交
{
dist2 = pow(xArray[i] - x, 2) + pow(yArray[i] - y, 2);
r2 = pow(rArray[i] + r, 2);
if (dist2 < r2)
{
isOk = 0;//默认isOk=1;若相交的话就变为0;
break;//数组中有圆与尝试圆相交的话就直接跳出for循环,进入下面的if语句
}
}
if (isOk == 1)/*上面for循环完了也没有出发isOk=0,就说明没有圆相交,不相交就再判断是否达到最大半径,
但是注意是isOk==1,不是isOk=1,否则判断无效*/
issmall = 1;//不相交和相切就说明没有达到最大半径
while (issmall == 1&&r<60)//要让画的圆的半径在不大于50且不与其他圆相交的基础上尽量大,issmall==1就说明圆还没有达到最大半径
{
r += 1;//半径逐渐增大直到相切
for (int i = 0; i < circleNum; i++)//判断数组中的圆与半径+1的圆是否相交
{
dist2 = pow(xArray[i] - x, 2) + pow(yArray[i] - y, 2);
r2 = pow(rArray[i] + r, 2);
if (dist2 < r2)//相交则说明半径太大了,这时,半径-1就不会相交了
{
issmall = 0;
r = r - 1;
break;
}
if (dist2 == r2)//相切则说明正好合适,半径不需要再-1
{
issmall = 0;
break;//break只能跳出for循环,要再终结while循环就要控制issmall
}
}
}
if (isOk == 1&&issmall==0)//不相交且达到最大半径就可以把数值放入数组中并且画圆了
{
xArray[circleNum] = x;//是xArray[circleNum]而不是xArray[i],合格的数值是要放进数组中最新的空位里
yArray[circleNum] = y;
rArray[circleNum] = r;
if (DrawMode == 1)
Drawcircle1(xArray[circleNum], yArray[circleNum], rArray[circleNum]);
if (DrawMode == 2)
Drawcircle2(xArray[circleNum], yArray[circleNum], rArray[circleNum]);
if (DrawMode == 3)
Drawcircle3(xArray[circleNum], yArray[circleNum], rArray[circleNum]);
if (DrawMode == 4)
Drawcircle4(xArray[circleNum], yArray[circleNum], rArray[circleNum]);
circleNum++;
Sleep(30);//画一个圆就停一下,要不然会直接画完
}
else//相交的话就continue进入继续while循环
{
isOk = 1;
}
}
_getch();
closegraph();
return 0;
}
/*
启示:
1.本来想通过数学计算直接算得圆的最大半径,但是用程序表达会比较复杂,所以直接用“笨方法”让圆不断+1来增大,
对于人来说是笨方法但是对于计算机来说未必
2.if(isOk==1)if(isOk=1)是完全不一样的
3.有时候程序运行了没有达到预期中的效果,可能是语法出错如2,可能是设计思路不对,但也有可能是数值不对,比如
如果一开始没有随便画个圆放入数组中后让circleNum为1的话,就无法进入for循环,因为不满足i<circleNum,这类错
误可以通过设置断点逐语句来运行发现
4.很多时候要使用到嵌套循环,比如while里嵌for,break只能终止一层循环,而通过对数值比如isOk/issmall等的控制就可以控制外层循环
5.有些反复使用的代码可以用函数封装,增加代码的可读性,比如为判断两个圆是否相交而设个函数
*/