一、屏幕操作函数
1. clrscr()清除字符窗口函数
2. window()字符窗口函数
3. gotoxy()光标定位函数
4. clreol() 清除光标行尾字符函数
5. insline() 插入空行函数
6. delline() 删除一行函数
7. gettext() 拷进文字函数
8. puttext() 拷出文字函数
9. movetext() 移动文字函数
二、字符属性函数
10. textmode() 文本模式函数
11. highvideo()高亮度函数
12. lowvideo() 低亮度函数
13. normvideo(void);
14. textcolor() 文本颜色函数
15. textattr() 文本属性函数
16.textbackground() 文本背景函数
三、 屏显状态函数
17. wherex() 光标处x坐标函数
18. wherey() 光标处y坐标函数
19. gettextinfo() 获取文本窗口信息函数
在Borland C++里面提供了字符屏幕和图形函数。字符屏幕的核心是窗口(Window),它是屏幕的活动部分,字符输出或显示在活动窗口中进行。窗口在缺省时,就是整个屏幕。窗口可以根据需要指定其大小。同样,对图形函数的操作,也提供了(Viewport)。也就是说图形函数的操作都是在视口上进行。图形视口与字符窗口具有相同的特性,用户可以在屏幕上定义大小不同的视口,若不定义视口大小,它就是整个屏幕。
窗口是在字符屏幕下的概念,只有字符才能在窗口中显示出来,这时用户可以访问的最小单位为一个字符。视口是在图形屏幕状态下的概念,文本与图形都可以在视口上显示,用户可访问的最小单位是一个像素(像素这一术语最初用来指显示器上最小的、单独的发光点单元。然而现在,其含义拓宽为指图形显示器上的最小可访问点)。
字符和图形状态下,屏幕上的位置都是由它们的行与列所决定的。有一点须指出:字符状态左上角坐标为(1,1),但图形左上角坐标为(0,0)。
了解字符屏幕和图形函数与窗口和视口的关系是很重要的。例如,字符屏幕 光标位置函数gotoxy()将光标移到窗口的x,y位置上,这未必是相对于整个屏幕。下面介绍常用的几类字符屏幕函数的功能用途、操作方法及其例行程序。
一、屏幕操作函数
编写程序绘图经常要用到对字符屏幕进行操作。例如,在往屏幕上写字符之前,首先要将屏幕清除干净。又如,有时需要在屏幕上多处写上肉中刺样的字符内容,这时最好用屏幕拷贝来高效率地完成这一任务。对这些操作,Borland C++提供了一系列字符屏幕操作函数来实现。
1. clrscr()清除字符窗口函数
功能:函数clrscr()清除整个当前字符窗口,并且把光标定位于左上角(1,1)处。
用法:此函数调用方式为 void clrscr(void);
说明:括号中void 表示无参数。
该函数相应的头文件为conio.h
返回值:无
例:使用这个函数的例子见4.clreol()函数的实例中。
2. window()字符窗口函数
功能: 函数window()用于在指定位置建立一个字符窗口。
用法: 此函数调用方式为 void window(int left,int top,int right,int bottom);
说明: 函数中参数left,top为窗口左上角坐标;right,bottom为其右下角坐标。
若有一个坐标是无效的,则window()函数不起作用。一旦该函数调用成功,那么所有定位坐标都是相对于窗口的,而不是相对于整个屏幕。但是建立窗口所用的坐标总是相对整个屏幕的绝对坐标,而不是相对当前窗口的相对坐标。这样用户就可以根据各种需要建立多个互不嵌套的窗口。
此函数的头文件为conio.h。
返回值:无
例: 调用这个函数的实现例见3.gotoxy()函数的例子中。
3. gotoxy()光标定位函数
功能: 函数gotoxy()将字屏幕上的光标移到当前窗口指定的位置上。
用法: 这个函数调用方式为void gotoxy(int x,int y);
说明: 括号里x,y是, 光标定位的坐标,如果其中一个坐标值无效(如坐标超界),那么光标不会移动。
此函数在字符状态(有时称为文本状态)下经常用到 ,其相应的头文件为conio.h
返回值:无
例: 下面程序建立两个窗口,然后在窗口里显示字符,字符的位置是调用该函数确定的。
#include"conio.h>
void border(int startx,int starty,int endx,int endy)
{
register int i;
gotoxy(1,1);
for(i=0;i<=endx-startx;i++)
putch('-');
gotoxy(1,endy-starty);
for(i=0;i<=endx-startx;i++)
putch('-');
for(i=2;i<=endy-starty;i++){
gotoxy(1,i);
putch('1');
gotoxy(endx-startx+1,i);
putch('1');
}
}
main()
{
void border(int,int,int,int);
clrscr();
window(6,8,38,12);
border(6,8,38,12);
gotoxy(2,2);
printf("window 1");
window(8,16,40,24);
border(8,16,40,24);
gotoxy(3,2);
printf("window 2");
getch();
}
4. clreol() 清除光标行尾字符函数
功能: 函数clreol()在当前字符窗口中清除从光标位置到行尾的所有字符,而光标位置保持不变。
用法: 它的调用方式为void clreol(void);
说明: 此函数的相应头文件为 conio.h
返回值:无
例: 程序中使用了函数clreol()和clrscr()
#include "conio.h>
void main()
{
register int i;
gotoxy(6,8);
printf("This is a test of the clreol() function.");
getch();
gotoxy(6,8);
clreol();
for(i=0;i<20;i++)
printf("Hellon");
getch();
clrscr();
}
5. insline() 插入空行函数
功能: 函数insline()插入一空行到当前光标所在行上,同时光标以下的所有行都向下顺移一行。
用法: 此函数的调用方式为void insline(void);
说明: 该函数只用于文本方式,并且在当了符窗口才有效。
这个函数的对应头文件是 conio.h
返回值:无
例: 程序给出了insline()函数的用法。
#include "conio.h"
void main()
{
registser int i;
clrscr();
for(i=1;i<24;i++)
{
gotoxy(1,i);
printf("This is line %dn",i);
}
getch();
gotoxy(1,10);
insline();
getch();
}
6. delline() 删除一行函数
功能: 函数delline()删除当前窗口内光标所在行,同时把该行下面 所有行都上移一行。
用法: 此函数调用方式为 void delline(void);
说明: 注意,如果当前窗口小于整个屏幕,那么该函数只影响到窗口内的字符。
这个函数相应的头部文件是conio.h
返回值: 无
例:先在屏幕上显示16行文字,然后删除第4行
#include "conio.h"
void main()
{
register int i;
clrscr();
for(i=0;i<16;i++) printf("line %dn",i);
getch();
gotoxy(1,4);
delline();
getch();
}
7.gettext() 拷进文字函数
功能: 函数gettext()用于文本状态下将屏幕上矩形域内的文字拷进内存。
用法: 该函数调用方式为 int gettext(int left,int top,int right,int bottom,void *buffer);
说明: 函数中参数left,top为矩形区域的左上角坐标,right,bottom为其右下角坐标,这些坐标是屏幕的绝对坐标,不是窗口的相对坐标。buffer指针必须指向一个足够保存该矩形域内文字的内存。所用内存大小按下式计算:
点头用字节数=矩形哉内的行数×矩形域的列数×2
这里将行数乘以列数再乘以2的原因是保存屏幕上每个字符要用两个字节存储单元,一个字节存储单元存放字符本身,而另一个存放其属性。
此函数相应的头文件是 conio.h
返回值: 若函数调用成功则返回1,否则返顺0。
例: 把屏幕左上角点(1,1)和右下角点(10,10)的区域拷贝到buf指向的内存中去。
buf=(char *)malloc(10*10*2);
if(!buf)gettext(1,1,10,10,buf);
8. puttext() 拷出文字函数
功能: 函数puttext()把先前由gettext()保存到buffer指向的内存中的文字拷出到屏幕上一个矩形区域中。
用法: 此函数调用方式为 int puttext(int left,int top,int right,int bottom,void *buffer);
说明: 函数里left,top为给出的屏幕上矩形区域的左上角点,right,bottom为其右下角点,其坐标是用屏幕的绝对坐标,而不是用窗口的相对坐标。
该函数相应的头文件为conio.h
返回值: 函数调用成功返回值为1,否则返回0。
例: 屏幕上某个区域内容拷进buf指向的内存中,然后又将这些文字拷出到屏幕上新位置。
buf=(char *)malloc(10*10*2);
gettext(1,1,10,10,buf);
puttext(16,16,30,30,buf);
9. movetext() 移动文字函数
功能: 函数movetext()将屏幕上一个矩形区域的文字移到另一个区域上。
用法: 该函数调用方式为 int movetext(int left,int top,int right,int bottom,int newleft,int newtop);
说明: 上面left,top为矩形区域上角坐标,right,bottom为其右下角坐标,newleft,newright为移动到区域左上角坐标。这些坐标是屏幕的绝对坐标,不是窗口的相对坐标。
若要把屏幕上一段文字移到屏幕的另一位置,那么使用movetext()函数比用gettext()然后再用puttext()效率更高。
此函数相应的头文件是conio.h
返回值: 如果有一个以上坐标无效,那么函数返回值为0,否则返回1。
列: 把屏幕左上角点(8,8),右下角点(20,20)的矩形区域文字移动到左上角点(10,10)的位置上:
movetext(8,8,20,20,10,10);
10. textmode() 文本模式函数
功能: 函数textmode()针屏幕设置为文本模式(或者说字符状态)。
用法: 函数调用方式为 void textmode(int mode);
说明: 参数mode必须为表1-2中所示的模式之一⑴以用模式名(符号值),也可以用其等价的整数值。
表1-2 文本模式
----------------------------------------------------------------
模式名(符号值) 等价整数值 说 明
BW40 0 40列黑白
C 40 1 40列彩色
BW80 2 80列黑白
C 80 3 80列彩色
MONO 7 80列单色
LASTMODE -1 上次模式
----------------------------------------------------------------
调用该函数后,屏幕复位,并且所有字符的属性恢复其缺省值。
此函数对应的头文件是conio.h
返回值: 无
例: 把屏幕设置为80列彩色模式
textmode(C80);
二、字符属性函数
用户可以设置字符显示的高亮度或低亮度的写的符闪烁及其背景颜色等。具有这些操作的函数称为字符属性函数。除了仅支持单模式和单色的显示卡外,字符属性函数适用于其余所有的显示卡。
11. highvideo()高亮度函数
功能: 函数highvideo()设置屏幕为高亮度显示。
用法: 此函数调用方式为void highvideo(void);
说明: 调用该函数后,写到屏幕上的字符是高亮度的。此函数只适用于文本模式状态(或说字符屏幕状态)。
这个函数对应的头文件为 conio.h
返回值: 无
例: 设置屏幕显示为高亮度的。
highvideo();
12. lowvideo() 低亮度函数
功能: 函数lowvideo()设置屏幕为低亮度显示。
用法: 该函数调用方式为void lowvideo(void);
说明: 调用该函数后,此时写到屏幕上的字符是低亮度的。这个函数只适用于文本模式状态(或说字符屏幕状态)。
此函数相应的头文件是 conio.h
返回值: 无
例: 设置屏幕显示为低亮度的
lowvideo();
13. normvideo(void);
功能: 函数normvideo()设置屏幕为正常亮度显示。
用法: 这个函数调用方式为void normvideo(void);
说明: 调用该函数后,此时写到屏幕上的字符是正常亮度的,该函数只适用于文本模式状态(或说字符状屏幕状态)。
此函数相应的头文件为conio.h
返回值: 无
例: 设置屏幕显示为正常亮度。
normvideo();
14. textcolor() 文本颜色函数
功能: 函数textcolor()设置字符屏幕下文本颜色(或字符颜色),它也可以用于使字符闪烁。
用法: 这个函数调用方式为void textcolor(int color);
说明: 函数中参数color的有效值可取表1-3中的颜色名(即宏名)或等价值。
表1-3 颜色名与等价值
---------------------------------------------------
名 等价值 含 义
BLACK 0 黑
BLUE 1 蓝
GREEN 2 绿
CYAN 3 青
RED 4 红
MAGENTA 5 洋红
BROWN 6 棕
LIGHTGRAY 7 淡灰
DRAKGRAY 8 深灰
LIGHTBLUE 9 淡蓝
LIGHTGREEN 10 淡绿
LIGHTCYAN 11 淡青
LIGHTRED 12 淡红
LIGHTMAGENTA 13 淡洋红
YELLOW 14 黄
WHITE 15 白
BLINK 128 闪烁
------------------------------------------------------------
textcolor()函数执行后,只影响其后输出探险符颜色,而不改变已经在当前屏幕上的其它字符颜色。显然,如果需要输出的字符闪烁,只要将函数中参数color取为BLINK即可,如果要使字符带颜色闪烁,就必须将所选的颜色值与128作“或”运算。
此函数相应的头文件是 conio.h
返回值: 无
例: 下面程序段中第一条语句使输出的字符闪烁,第三条语句使字符输出为经色同时闪烁:
textcolor(BLINK);
printf("hello");
textcolor(RED|BLINK);
15. textattr() 文本属性函数
功能: 函数textattr()用于设置文本属性,即字符背景颜色、字符本身颜色和字符闪烁与否。
用法: 函数调用方式为void textattr(int attribute);
说明: 设置字符背景颜色属性字节的最简单方法是,用所选的背景颜色值乘以16再与字符颜色值作按位或(OR)运算。例如需要红色背景、绿色字符,就设置成RED*16|GREEN,若还要字符闪烁,就把背景颜色值、字符颜色值与闪烁值一起
按位作或运算。如蓝背景、黄字符且闪烁,就设置成为:
YELLO|128|BLUE*16
第0位用于设置字符颜色。
此函数相应的头文件为conio.h
返回值: 无
例: 设置背景为蓝色、字符为红色并且字符闪烁:
textattr(RED|128|BLUE*16);
16.textbackground() 文本背景函数
功能: 函数textbackground()设置字符屏幕下文本背景颜色(或字符背景颜色)。
用法: 此函数调用方式为void textbackground(int bcolor);
说明: 参数bcolor 的有效值取表1-4背景颜色(即宏名)或等价值。
表1-4 背景颜色与等价值
-------------------------------------------------
背景颜色 等价值 含 义
-------------------------------------------------
BLACK 0 黑
BLUE 1 蓝
GREEN 2 绿
CYAN 3 青
RED 4 红
MAGENTA 5 洋红
BROWN 6 棕
-------------------------------------------------
调用该函数只影响后续写的字符背景颜色,而不改变当前显示在屏幕上的字符背景颜色。
这个函数对应的头文件是conio.h
返回值: 无
例: 设置文本背景颜色为蓝色:
textbackground(BLUE));
三、 屏显状态函数
这里提供三个在文本模式下屏幕显示状态的函数
17. wherex() 光标处x坐标函数
功能: 函数wherex()返回当前窗口中光标处横向坐标。
用法: 此函数调用方式为int wherex(void);
说明: 这个函数调用无参数,其对应的头文件是conio.h
返回值: 函数调用成功,返回光标处x坐标值。
例: 调用这个函数的实例见18.wherey()函数的例中。
18. wherey() 光标处y坐标函数
功能: 函数wherey()返回当前窗口中光标处纵向坐标。
用法: 该函数调用方式为int wherey(void);
说明: 此函数调用无参数,其相应的头文件是conio.h
返回值: 函数调用成功,返回光标处y坐标值。
例: 调作函数wherex()与wherey(),返回当前光标处x坐标与y坐标,并赋给整型变量xpos ,ypos。
int xpos,ypos;
xpos=wherex();
ypos=wherey();
19. gettextinfo() 获取文本窗口信息函数
功能: 函数gettextinfo()获取当前文本窗口信息,并存放在实参结构中。
用法: 函数调用方式为void gettextinfo(struct text-info *info);
说明: 函数中参数info 为struct text-info结构型指针,struct text-info结构在此函数相应的头文件中定义为:
struct text-info{
unsigned char winleft; // 窗口左上角x坐标
unsigned char wintop; // 窗口左上角y坐标
unsigned char winright; // 窗口右下角x坐标
unsigned char winbottom; // 窗口右下角y坐标
unsigned char attribute; // 文本属性
unsigned char normattr; // 正常属性
unsigned char currmode; // 当前屏显模式
unsigned char screenhight // 文本窗口高度(以行数计)
unsigned char screenwidth; // 文本窗口宽度(以字符个数计)
unsigned char curx; // 光标处x坐标
unsigned char cury; // 光标处y坐标
};
记住,调用函数gettextinfo()时,要传递struct text-info结构型指针或该结构的首地址,不要传递结构变量本身。
这个函数对应的头文件是conio.h
返回值: 返回文本窗口角点坐标、高宽度、文本属性等值,并存放在info所指向的结构变量中。
例: 程序语句说明如何正确调用gettextinfo()函数:
struct text-info win-status;
gettextinfo(&win-status);
一、确定显示卡
二、选择显示模式
三、图形显示
20. detectgraph() 显示卡检测函数
21. initgraph() 图形初始化函数
22. getdrivername() 获取图形驱动程序名的指针
23. getgraphmode() 获取图形模式函数
24. getmoderange()获取模式值范围函数
25. getmaxmode()获取最大显示模式函数
26. getmodename()获取显示模式名函数
27. graphdefaults()图形设置复位缺省值函数
28. setgraphmode() 设置图形模式函数
29. restorecrtmode() 恢复文本显示模式函数
30. graphresult() 图形操作结果函数
31. grpaherrormsg() 图形错误信息函数
32. setgraphbufsize()设置图形缓冲区大小函数
33. setactivepage() 设置可输出显示页函数
34. setvisualpage() 设置可见显示页数
35. closegraph()关闭图形模式函数
一、确定显示卡
微机系统显示部分由显示器(monitor)和显示卡(adapter)两部分组成。显示器是独立于主机的一种外部设备,显示卡或称显示适配卡,也有的称图形卡,是插在主机上的一块电路板。但也有的显示卡与主机板设计在一起。显示卡包括寄存器组、存储器和控制电路三大部分。其中存储器又包括显示RAM和ROM BIOS两部分,微机对显示屏幕的所有操作都是通过显示卡来实现的。因此要进行图形显示 ,首先要确定计算机上安装的是何种显示卡。一种方法是询问计算机或终端使用者,确定将要使用的显示卡类型。这种方法很难,因为甚至专业程序员也不总是能确定他正在使用什么样的硬件。另一种方法是用软件查询硬件以识别当前的配置。如果有一些识别硬件的标准,这就很简单了。在Borland C中对现在所使用的各种显示卡提供了支持,这只要调用detectgraph()函数就可以了,该函数为程序员确定计算机上使用的显示卡类型。
二、选择显示模式
显示模式是指显示卡支持的分辨率与相应的颜色配置。每台计算机都配置了某种类型显示卡,可以为该显示卡指定显示模式。
三、图形显示
进行图形显示首先要确定显示卡,然后选择其显示模式。这些工作都可以调用图形功能函数来完成,其实就是把适合于显示卡的图形驱动程序装入内存。如果图形驱动程序未装入内存,那么图形函数就不能操作。
20. detectgraph() 显示卡检测函数
功能: 函数detectgraph()在计算机上安装有显示卡的情况下,测定其显示卡的类型。
用法: 此函数调用方式为void detectgraph(int *driver,int *mode);
说明: 函数把driver所指向的整型变量设置为图形驱动程序的代码,把mode所指向的整型变量设置为显示卡支持的最高有效模式(即该显示卡能支持的最高分辨率)。
该函数相应的头文件为graphics.h
返回值: 返回适合于该显示卡的图形驱动程序的代码(也称等价值),并存放在driver指向的变量中。若计算机系统中无图形硬件,则由driver指向的变量设置为-2。
例: 检测计算机是否装有显示卡:
int driver,mode;
detectgraph(&driver,&mode);
if(driver==-2)
{
printf("no graphics adapter in the computer");
exit(1);
}
21. initgraph() 图形初始化函数
功能: 函数initgraph()用于初始化图形系统,把适合的图形驱动程序装入内存,设置图形函数所用的显示模式。
用法: 该函数调用方式为void initgraph(int *driver,int *mode,char *path);
说明: 1) 函数中参数driver指向图形驱动程序(或者等价值)。
在头部文件graphics.h中定义了图形驱动程序的宏名与其等价 ,如下:
宏 名 等价值
------------------------------
DETECT 0
CGA 1
MCGA 2
EGA 3
EGA64 4
EGAMONO 5
IBM8514 6
HERCMONO 7
ATT400 8
VGA 9
PC3270 10
--------------------------------
注:在现在的计算机中,上表中的许多显示卡已经过时,不再使用。
这样就不必担心图形驱动程序的准确名字,而只要用其等价值即可,若使用detect(即等价值0)时,initgraph()函数自动检测当前计算机中装有的显示卡类型,并且选用最大分辨率的显示模式。
2)参数mode指向显示模式或用等价值(风表1-5),mode所指的值必须是有效模式之一。
3)参数path指向图形驱动程序所在的路径,例如path="C:TCBG1".若没有指定路径,就在当前目录下寻找。
一般图形驱动程序包含在.BGI文件中,这些文件是系统可以得到的。这个函数对应的头文件是graphics.h。
返回值: 无
例: 调用initgraph()自动检测硬件图形系统,并选用最大分辨率显示模式。
init drver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
22. getdrivername() 获取图形驱动程序名的指针
功能: 函数getdrivername()返回指向当前图形驱动程序名的指针。
用法: 此函数调用方式为char *getdrivername(void);
说明: 本函数可以用来检测显示卡,但只能在initgraph()设置图形驱动程序和显示模式之后调用。
该函数相应的头文件为graphics.h
返回值: 返回一指针,指向含有当前图形驱动程序名的字符串。
例: 显示当前图形驱动程序名:
#include<graphics.h>
#include<stdio.h>
void main()
{
int graphdriver=DETECT,graphmode;
char *s;
initgraph(&graphdriver,&graphmode,"");
s=getdrivername();
outtext("Using driver:");
outtext(s);
getch();
closegraph();
}
23. getgraphmode() 获取图形模式函数
功能: 函数getgrapgmode()返回当前图形模式。
用法: 该函数调用方式为int getgraphmode(void);
说明: getgraphmode()函数无参数调用。
这个函数对应的头文件是graphics.h
返回值: 返回initgraph()或setgraphmode()所设置的当前图形模式值。
例: 显示当前图形模式的代码:
printf("graphics mode is %d",getgraphmode());
24. getmoderange()获取模式值范围函数
功能: 函数getmoderange()返回指定的图形驱动程序能够支持的最低和最高模式值。
用法: 函数调用方式为 void getmoderange(int driver,int *lowmode,int himode);
说明: 参数driver是用来调用此函数时,指定图形驱动程序等价值或宏名。
其有效值如下:
-------------------------------------
宏 名 等价值
-------------------------------------
DETECT 0
CGA 1
MCGA 2
EGA 3
EGA64 4
EGAMONO 5
IBM8514 6
HERCMONO 7
ATT400 8
VGA 9
PC3270 10
-------------------------------------
注:上表中的许多显示卡在现在的计算机上已经过时,仅作参考。
该函数想应的头文件为graphics.h
返回值: 返回的最小和最大有效值存放在参数指针lowmode和himode分别指向的整型变量中。
例: 显示当前图形硬件的显示模式的范围值:
#include"graphics.h"
void main()
{
int driver,mode;
int low,high;
mode=0;
initgraph(&driver,&mode,"");
getmoderange(driver,&low,&high);
printf("mode range:%d--%d,low,high);
getch();
rstorecrtmode();
}
25. getmaxmode()获取最大显示模式函数
功能: 函数getmaxmode()返回当前加载的图形驱动程序所支持的最大有效显示模式。
用法: 函数调用方式为int getmaxmode(void);
说明:本函数无参数调用,返回图形驱动程序所支持的最大显示模式,所有图形驱动程序支持从0到getmaxmode()函数返回值中的任一整 数值(对应的显示模式)。
这个函数对应的头文件是graphics.h
返回值:返回图形驱动程序所支持的显示模式最大值。
例: 显示当前最大显示模式:
printf("The maxmode of this driver is %dn",getmaxmode());
26. getmodename()获取显示模式名函数
功能: 函数getmodename()可获取当前图形驱动程序支持的指定显示模式的名字。
用法: 此函数调用方式为char *getmodename(int modecode);
说明: 参数modecode为整型值。用以指定一显示模式值调用该函数。
这个函数对应的头文件graphics.h
返回值: 返回指定模式值的显示模式名。
例: 显示当前最大显示模式名:
#include<graphics.h>
#include<stdio.h>
void main()
{
int graphdriver=DETECT,graphmode;
int modecode;
char *s;
initgraph(&graphdriver,&graphmode,"");
modecode=getmaxmode();
s=getmodename(modecode);
outtext("The maxmode name is:");
outtext(s);
getch();
closegraph();
}
27. graphdefaults()图形设置复位缺省值函数
功能: 函数grpahdefaults()把所有图形设置复位为它们的缺省值,这包括把图形视口复位为全屏幕;当前位置定位在0,0;调色板、背景色和绘图色都被复位;填充颜色、填 充图样、文本文字和排齐方式都返回到它位的缺省值。
用法: 此函数调用方式为void graphdefaults(void);
说明: 该函数无参数调用。
这个函数相应的头文件为graphics.h
返回值: 无
例: 将图形系统恢复为其缺省值:
graphdefaults();
28. setgraphmode() 设置图形模式函数
功能: 函数setgraphmode()用当前图形驱动程序有效的图形模式调用,一旦被调用,setgraphmode()选择一个新的图形模式。注意,图形显示模式必须事先由initgraph()初始化。
用法: 该函数调用方式为void setgraphmode(int mode);
说明: 参数mode调用时为指定的模式值。
此函数相应的头部文件是graphics.h
返回值: 无
例: 把VGA图形卡设置为VGAMED模式:
setgraphmode(VGAMED); // 图形系统已经初始化
29. restorecrtmode() 恢复文本显示模式函数
功能: 函数restrecrtmode()将显示模式恢复到调用initgraph()时检测出的初始文本模式。
用法: 这个函数调用方式为void restorecrtmode(void);
说明: 函数restorecrtmode()和setgraphmode()函数一起使用,可以实现文本与图形显示之间的切换。
此函数对应的头文件为graphics.h
返回值: 无
例: 恢复显示模式为初始文本模式:
restorecrtmode();
30. graphresult() 图形操作结果函数
功能: 函数graphresult()函数返回最后一次图形操作的代码。
用法: 此函数调用方式为int graphresult(void);
说明: C为图形设置了代码,它们是从-15到0的整数值。其含义见表1-6。
调用该函数时,出错状态被复位为0,所以返回值(代码)最好存于变量中,以供需要时检测,
进行下一步图形操作。
图形操作信息名称
四、图形和图像函数
(一) 像素函数
56. putpiel() 画像素点函数
57. getpixel()返回像素色函数
(二) 直线和线型函数
58. line() 画线函数
59. lineto() 画线函数
60. linerel() 相对画线函数
61. setlinestyle() 设置线型函数
62. getlinesettings() 获取线型设置函数
63. setwritemode() 设置画线模式函数
(三)、多边形函数
64. rectangle() 画矩形函数
65. bar() 画条函数
66. bar3d() 画条块函数
67. drawpoly() 画多边形函数
(四)、 圆、弧和曲线函数
68. getaspectratio()获取纵横比函数
69. circle()画圆函数
70. arc() 画圆弧函数
71. ellipse()画椭圆弧函数
72. fillellipse() 画椭圆区函数
73. pieslice() 画扇区函数
74. sector() 画椭圆扇区函数
75. getarccoords()获取圆弧坐标函数
(五)、 填充函数
76. setfillstyle() 设置填充图样和颜色函数
77. setfillpattern() 设置用户图样函数
78. floodfill() 填充闭域函数
79. fillpoly() 填充多边形函数
80. getfillsettings() 获取填充设置函数
81. getfillpattern() 获取用户图样设置函数
(六)、图像函数
82. imagesize() 图像存储大小函数
83. getimage() 保存图像函数
84. putimage() 输出图像函数
四、图形和图像函数
对许多图形应用程序,直线和曲线是非常有用的。但对有些图形只能靠操作单个像素才能画出。当然如果没有画像素的功能,就无法操作直线和曲线的函数。而且通过大规模使用像素功能,整个图形就可以保存、写、擦除和与屏幕上的原有图形进行叠加。
(一) 像素函数
56. putpixel() 画像素点函数
功能: 函数putpixel() 在图形模式下屏幕上画一个像素点。
用法: 函数调用方式为void putpixel(int x,int y,int color);
说明: 参数x,y为像素点的坐标,color是该像素点的颜色,它可以是颜色符号名,也可以是整型色彩值。
此函数相应的头文件是graphics.h
返回值: 无
例: 在屏幕上(6,8)处画一个红色像素点:
putpixel(6,8,RED);
57. getpixel()返回像素色函数
功能: 函数getpixel()返回像素点颜色值。
用法: 该函数调用方式为int getpixel(int x,int y);
说明: 参数x,y为像素点坐标。
函数的返回值可以不反映实际彩色值,这取决于调色板的设置情况(参见setpalette()函数)。
这个函数相应的头文件为graphics.h
返回值: 返回一个像素点色彩值。
例: 把屏幕上(8,6)点的像素颜色值赋给变量color。
color=getpixel(8,6);
(二) 直线和线型函数
有三个画直线的函数,即line(),lineto(),linerel()。这些直线使用整型坐标,并相对于当前图形视口,但不一定受视口限制,如果视口裁剪标志clip为真,那么直线将受到视口边缘截断;如果clip为假,即使终点坐标或新的当前位置在图形视口或屏幕极限之外,直线截断到屏幕极限。
有两种线宽及几种线型可供选择,也可以自己定义线图样。下面分别介绍直线和线型函数。
58. line() 画线函数
功能: 函数line()使用当前绘图色、线型及线宽,在给定的两点间画一直线。
用法: 该函数调用方式为void line(int startx,int starty,int endx,int endy);
说明: 参数startx,starty为起点坐标,endx,endy为终点坐标,函数调用前后,图形状态下屏幕光标(一般不可见)当前位置不改变。
此函数相应的头文件为graphics.h
返回值: 无
例: 见函数60.linerel()中的实例。
59. lineto() 画线函数
功能: 函数lineto()使用当前绘图色、线型及线宽,从当前位置画一直线到指定位置。
用法: 此函数调用方式为void lineto(int x,int y);
说明: 参数x,y为指定点的坐标,函数调用后,当前位置改变到指定点(x,y)。
该函数对应的头文件为graphics.h
返回值: 无
例: 见函数60.linerel()中的实例。
60.linerel() 相对画线函数
功能: 函数linerel() 使用当前绘图色、线型及线宽,从当前位置开始,按指定的水平和垂直偏移距离画一直线。
用法: 这个函数调用方式为void linerel(int dx,int dy);
说明: 参数dx,dy分别是水平偏移距离和垂直偏移距离。
函数调用后,当前位置变为增加偏移距离后的位置,例如,原来的位置是(8,6),调用函数linerel(10,18)后,当前位置为(18,24)。
返回值:无
例: 下面的程序为画线函数调用实例:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
setcolor(15);
line(66,66,88,88);
lineto(100,100);
linerel(36,64);
getch();
restorecrtmode();
}
61. setlinestyle() 设置线型函数
功能: setlinestyle() 为画线函数设置当前线型,包括线型、线图样和线宽。
用法: setlinestyle() 函数调用方式为void setlinestyle(int stly,unsigned pattern,int width);
说明: 参数style为线型取值,也可以用相应名称表示,如表1-10中所示。
参数pattern用于自定义线图样,它是16位(bit)字,只有当style=USERBIT_LINE(值为1)时,pattern的值才有意义,使用用户自定义线图样,与图样中“1”位对应的像素显示,因此,pattern=0xFFFF,则画实线;pattern=0x9999,则画每隔两个像素交替显示的虚线,如果要画长虚线,那么pattern的值可为0xFF00和0xF00F,当style不为USERBIT_LINE值时,虽然pattern的值不起作用,但扔须为它提供一个值,一般取为0。
参数wigth用来设定线宽,其取值见表1-11,表中给出了两个值,即1和3,实际上,线宽取值为2也是可以接受的。
若用非法参数调用setlinestyle()函数,那么graphresult()会返回错误代码,并且当前线型继续有效。
Turbo C提供的线型与线宽定义在头文件graphics.h中,表1-10和1-11分别列出了参数的取值与含义。
表1-10 线型
-----------------------------------------------------
名 称 取 值 含 义
-----------------------------------------------------
SOLID_LINE 0 实线
DOTTED_LINE 1 点线
CNTER_LINE 2 中心线
DASHED_LINE 3 虚线
USERBIT_LINE 4 用户自定义线型
-----------------------------------------------------
表1-11 线宽
-----------------------------------------------------------
名 称 取 值 说 明
-----------------------------------------------------------
NORM_WIDTH(常宽) 1 一个像素宽(缺省值)
THICK_WIDTH(加宽) 3 三个像素宽
-----------------------------------------------------------
这个函数的头文件是graphics.h
返回值: 无
例: 下面的程序显示了BC中所提供的线型图样:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
for(i=0;i<4;i++)
{
setlinestyle(i,0,1);
line(i*50,200,i*50+60,200)
}
getch();
restorecrtmode();
}
62. getlinesettings() 获取线型设置函数
功能: 函数getlinesettings() 用当前设置的线型、线图样和线宽填 写linesettingstype型结构。
用法: 函数调用方式为void getlinesettings(struct linesettingstype *info);
说明: 此函数调用执行后,当前的线型、线图样和线宽值被装入info指向的结构里,从而可从该结构中获得线型设置。
linesettingstype型结构定义如下:
struct linesettingstype {
int linestyle;
unsigned upattern;
int thickness;
};
其中linestyle用于存放线型,线型值为表1-10中的各值之一。
upattern用为装入用户自定义线图样,这是16位字,每一位等于一个像素,如果哪个位被设置,那么该像素打开,否则关闭。
thickness为线宽值存放的变量,可参见表1-11。
getlinesettings()函数对应的头文件为graphics.h
返回值: 返回的线型设置存放在info指向的结构中。
例: 把当前线型的设置写入info结构:
struct linesettingstype info;
getlinesettings(&info);
63.setwritemode() 设置画线模式函数
功能: 函数setwritemode() 设置画线模式
用法: 函数调用方式为 void setwritemode()(int mode);
说明: 参数mode只有两个取值0和1,若mode为0,则新画的线将复盖屏幕上原有的图形,此为缺省画线输出模式。如果mode为1,那么新画的像素点与原有图形的像素点先进行异或(XOR)运算,然后输出到屏幕上,使用这种画线输出模式,第二次画同一图形时,将擦除该图形。调用setwritemode()设置的画线输出模式只影响函数line(),lineto(),linerel(),recangle()和drawpoly()。
setwritemode()函数对应的头文件是graphics.h
返回值: 无
例: 设置画线输出模式为0:
setwritemode(0);
(三)、多边形函数
对多边形,无疑可用画直线函数来画出它,但直接提供画多边形的函数会给用户很大方便。最常见的多边形有矩形、矩形块(或称条形)、多边形和多边形块,我们还把长方形条块也放到这里一起考虑,虽然它不是多边形,但它的特例就是矩形(块)。下面直接介绍画多边形的函数。
64. rectangle() 画矩形函数
功能: 函数rectangle() 用当前绘图色、线型及线宽,画一个给定左上角与右下角的矩形(正方形或长方形)。
用法: 此函数调用方式为void rectangle(int left,int top,int right,int bottom);
说明: 参数left,top是左上角点坐标,right,bottom是右下角点坐标。如果有一个以上角点不在当前图形视口内,且裁剪标志clip设置的是真(1),那么调用该函数后,只有在图形视口内的矩形部分才被画出。
这个函数对应的头文件为graphics.h
返回值: 无
例: 下面的程序画一些矩形实例:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgrpah(&driver,&mode,"");
rectangle(80,80,220,200);
rectangle(140,99,180,300);
rectangle(6,6,88,88);
rectangle(168,72,260,360);
getch();
restorecrtmode();
}
65. bar() 画条函数
功能: 函数bar()用当前填充图样和填充色(注意不是给图色)画出一个指定上左上角与右下角的实心长条形(长方块或正方块),但没有四条边线)。
用法: bar()函数调用方式为void bar(int left,int top,int right,int bottom);
说明: 参数left,topright,bottom分别为左上角坐标与右下角坐标,它们和调用函数rectangle()的情形相同,调用此函数前,可用setfillstyle()或setfillpattern()设置当前填充图样和填充色。
注意此函数只画没有边线的条形,如果要画有边线的的条形,可调用下面的函数bar3d()来画,并将深度参数设为0,同时topflag参数要设置为真,否则该条形无顶边线。
这 应的头文件为graphics.h
返回值: 无
例: 见函数bar3d()中的实例。
66.bar3d() 画条块函数
功能: 函数bar3d() 使用当前绘图色、线型及线宽画出三维长方形条块,并用当前填充图样和填 充色填充该三维条块的表面。
用法: 此函数调用方式为void bar3d(int left,int top,int right,int bottom,int depth,int topflag);
说明: 参数left,top,right,bottom分另为左上角与右下角坐标,这与bar()函数中的一样。参数depth为条块的深度,以像素为单位,通常按宽度的四分之一计算。深度方向通过屏显纵横比调节为约45度(即这时x/y比设置为1:1)。
参数topflag相当于一个布尔参数,如果设置为1(真)那么条块上放一顶面;若设置为0(假),则三维条形就没有顶面,这样可使多个三维条形叠加在一起。
要使图形更加美观,可利用函数floodfill()或setfillpattern()来选择填充图样和填充色(参见本小节(五)填充函数 )。
bar3d()函数对应的头文件为graphics.h
返回值: 无
例: 下面的程序画一个条形和条块:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
setfillstyle(SOLID-FILL,GREEN);
bar(60,80,220,160);
setfillstyle(SOLID-FILL,RED);
bar3d(260,180,360,240,20,1);
getch();
restorecrtmode();
}
67. drawpoly() 画多边形函数
功能: 函数drawpoly() 用当前绘图色、线型及线宽,画一个给定若干点所定义的多边形。
用法: 此函数调用方式为void drawpoly(int pnumber,int *points);
说明: 参数pnumber为多边形的顶点数;参数points指向整型数组,该数组中是多边形所有顶点(x,y)坐标值,即一系列整数对,x坐标值在前。显然整型数组的维数至少为顶点数的2倍,在定义了多边形所有顶点的数组polypoints时,顶点数目可通过计算sizeof(polypoints)除以2倍的sizeof(int)得到,这里除以2倍的原因是每个顶点有两个整数坐标值。另外有一点要注意,画一个n个顶点的闭合图形,顶点数必须等于n+1,并且最后一点(第n+1)点坐标必须等于第一点的坐标。
drawpoly()函数对应的头文件为grpahics.h
返回值: 无
例: 下面的程序画一个封闭星形图与一个不封闭星形图:
#include<graphics.h>
void main()
{
int driver,mode;
static int polypoints1[18]={100,100,110,120,100,130,120,125,140,140,130,120,
140,110,120,115,100,100};
static int polypoints2[18]={180,100,210,120,200,130,220,125,240,140,230,120,
240,110,220,115,220,110};
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
drawpoly(9,polypoints1);
drawpoly(9,polypoints2);
getch();
restorecrtmode();
}
(四)、 圆、弧和曲线函数
在一个屏幕上画得很圆的图形到另一个屏幕上可能被压扁或拉长,这是因为每一种显示卡与之相应的显示模式都有一个纵横比。纵横比是指像素的水平方向大小与垂直方向大小的比值。如VGA显示卡由于偈素基本上是正方形,所以纵横比为1.000。
为了保证几何图形基本按预计情况显示在屏幕上,用屏显的纵横比来计算和纠正不同硬件及显示卡产生的畸变。计算纵横比所需要的水平方向和垂直方向的比例系数可调用函数getaspectratio()获得。
68. getaspectratio()获取纵横比函数
功能: 函数getaspectratio()返回x方向和y方向的比例系数,用这两个整型值可计算某一特定屏显的纵横比。
用法: 此函数调用方式为void getaspectratio(int xasp,int yasp);
说明: 参数xasp指向的变量存放返回的x方向比例系数;参数yasp指向的变量存放返回的y方向比例系数。通常y方向比例系数为10 000, x方向比例系数不大于10 000(这是因为大多数屏幕像素高比宽长)。
注意纵横比自动用作下面函数arc(),circle()和pieslice()中的标尺因子,使屏幕上圆或弧正常显示。但用ellipse()函数画椭圆必须调用本函数获取纵横比作为标尺因子,否则不予调整。纵横比可用于其它几何图形,目的是校正和显示图形。
getaspectratio()函数对应的头文件为graphics.h
返回值: 返回x与y方向比例系数分别存放在xasp和yasp所指向的变量中。
例: 下面的程序显示纵横比:
int xasp,yasp;
float aspectratio;
getaspectratio(&xasp,&yasp);
aspectratio=xasp/yasp;
printf("aspect ratio: %f",aspectratio);
69. circle()画圆函数
功能: 函数circle()使用当前绘图色并以实线画一个完整的圆。
用法:该函数调用方式为void circle(int x,int y,int radius);
说明: 参数x,y为圆心坐标,radius为圆半径,用像素个素表示。注意,调用circle()函数画圆时不用当前线型。
不同于ellipse()函数,只用单个半径radius参数调用circle()函数,故屏显纵横比可以自动调节,以产生正确的显示图。
此函数对应的头文件为graphics.h
返回值: 无
例: 画六个同心圆,圆心在(100,100)。
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
circle(100,100,10);
circle(100,100,20);
circle(100,100,30);
circle(100,100,40);
circle(100,100,50);
circle(100,100,60);
getch();
restorecrtmode();
}
70. arc() 画圆弧函数
功能: 函数arc()使用当前绘图色并以实线画一圆弧。
用法: 函数调用方式为void arc(int x,int y,int startangle,int endangle,int radius);
说明: 参数x,y为圆心坐标,startangle与endangle分别为起始角与终止角,radius为半径。圆心坐标和半径以像素个数给出,起始角和终止角以度为单位,0度位于右边,90度位于顶部,180度位于左边,底部是270度。同往常一样,360度与0度重合。角度按逆时针方向增加,但并不要求终止角一定比起始角大。例如指定300度和90度分别为起始角和终止角,与指定300度和450度分别为起始角和终止角可画出相同的弧。大于360度可作为参数,它将被化到0度 ̄360度范围里。函数arc()能画封闭圆,只要取起始角为0度,终止角为360度即可。此函数中,屏显纵横比可自动调节。
arc()函数对应的头文件为graphics.h
返回值: 无
例: 以(200,200)为圆心,100为半径,从0度到120度画圆弧:
#include<graphics.h
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&drivwer,&mode,"");
setcolor(WHITE);
arc(200,200,0,120,100);
getch();
restorecrtmode();
}
71. ellipse()画椭圆弧函数
功能: 函数ellipse()使用当前绘图色画一椭圆弧。
用法: 该函数调用方式为void ellipse(int x,int y,int startangle,int endangle,
int xradius,int yradius);
说明: 参数x,y为椭圆中心坐标,startangle和endangle为给定的起始角和终止角,xradius与yradius为椭圆的x轴半径与y轴半径,如果startangle为0 ,endangle等于360度,那么画出的是个完整的椭圆。ellipse()函数不同于arc()和circle()函数,屏显纵横比不能自动调节。若需要的是成比例的半径而不是特定的像素距离,则y轴距离必须调节为yradius*aspectratio(y轴半径乘以纵横比)。
此函数对应的头文件为graphics.h
返回值: 无
例: 在屏幕上画一个鸡蛋形的椭圆。
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
ellipse(200,100,0,360,80,40);
getch();
restorecrtmode();
}
72. fillellipse() 画椭圆区函数
功能: 函数fillellipse()使用当前绘图色画一椭圆,然后用当前填充色图样和填充色填充所画的椭圆。
用法: 此函数调用方式为void fillellipse(int x,int y,int xradius,int yradius);
说明: 参数x,y为椭圆中心坐标,xradius,yradius为水平轴半径和垂直轴半径。
这个函数对应的头文件为graphics.h
返回值: 无
例: 画一填充椭圆:
#include<graphics.h>
#include<stdio.h>
#define R 60
void main()
{
int driver,mode;
int xasp,yasp;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
fillellipse(getmaxx()/2,getaxy()/2,66,44);
getaspectratio(&xasp,&yasp);
fillellipse(R,R,R,R*(long)xasp/(long)yasp);
getch();
closegraph();
}
73. pieslice() 画扇区函数
功能: 函数pieslice()使用当前绘图色画一圆弧,并把弧两端与圆心分别连一直线段(即半径),然后用当前填图样和填充色进行填充,即得扇区。
用法: 这个函数调用方式为void pieslice(int x,int y,int startangle,int endangle,int radius);
说明: 函数pieslice()的操作类似于arc()函数(即同调用参数一样,只是函数名不同),因此调用此函数的详细说明参见函数arc()的相应内容。该函数对屏显纵横比能自动调节进行补偿。
pieslice()函数对应的头文件为graphics.h
返回值:无
例: 显示一个扇形图,每45度为一个不同的扇区:
#include<graphics.h>
void main()
{
int driver,mode;
int i,start,end;
driver=DETECT;
mode=0;
initgraph(&driver,mode,"");
start=0;
end=45;
for(i=0;i<8;i++)
{
setfillstyle(SOLID_FILL,i);
pieslice(260,200,start,end,100);
start+=45;
end+=45;
}
getch();
restorecrtmode();
}
74. sector() 画椭圆扇区函数
功能: 函数sector()先用当前绘图色画椭圆扇形轮廓,然后用当前填充图样和填充色进行填充,即得椭圆扇区。
用法: 该函数调用方式为void sector(int x,int y,int startangle,int endangle,int xradius,int yradius);
说明: 参数x,y为椭圆中心坐标,startangle和endangle为起始角与终止角,xradius与yradius是水平轴半径和垂直轴半径即长短轴。当startangle为0,endangle为360度时,调用此函数可画得一个完整的椭圆区。角度增加方向为反时针方向。设定填充图样和填充色,用setfillstyle()或setfillpattern()函数,若画轮廓线或填充扇区出现错误,则graphresult()函数返回值-6。对屏显纵横比,sector()函数不能自动调节补偿。
返回值: 无
例: 画出两个椭圆扇区:
#include<graphics.h>
#include<stdio.h>
#define R 80
void main()
{
int driver,mode;
int xasp,yasp;
initgraph(&driver,&mode,"");
sector(getmaxx()/2,getmaxy()/2,0,656,R,R);
getaspectratio(&xasp,&yasp);
setctor(getmaxx()/2,getmaxy()/2,180,135,R,R*(long)xasp/(long)yasp);
getch();
closegraph();
}
75. getarccoords()获取圆弧坐标函数
功能: 函数getarccoords()将最后一次调用arc()或ellipse()画的圆弧或椭圆弧的起终点坐标和中心坐标填入arccoordstype型结构里,进而从该结构中获取这些坐标值。
用法: getarccoords()函数调用方式为void getarccoords(struct arccoordstype *coordsp);
说明: 调用此函数填写coordsp指向的结构,从而获得起终点坐标和中心坐标值。它们可用于画弦、半径以及其它与圆弧端点相连的直线等。pieslice()函数就要用到这些值。如果最后一次调用的函数是circle(),那么getarccoords()将返回圆心坐标和起终点坐标即圆的位置。
arccoordstype型结构定义如下:
struct arccoordstype {
int x,y;
int xstart,ystart,xend,yend;
};
其中,x,y存放中心坐标;xstart,ystart,xend,yend分别存放起终点坐标。
值得注意的是,结构里起终点(xstart,ystart)与(xend,yend)坐标是像素值,不是角度值,这和调用arc()或ellipse()函数所用的不一样。当然中心坐标(x,y)与调用函数时所用的是一样的。
这个函数的头文件是graphics.h
返回值: 返回最后一次调用圆或椭圆函数的相应起终点与中心坐标值,并存放在coordsp指向的结构里。
例: 下面的程序画圆心在(100,100)的四分之一圆弧,然后于弧两端点之间连一直线。
#include<graphics.h>
void main()
{
int driver,mode;
struct arcccoordstype arcinfo;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
arc(100,100,0,90,88);
getarccoords(&arcinfo);
line(arcinfo.xstart,arcinfo.ystart,arcinfo.xend,arcinfo.yend);
getch();
restorecrtmode();
}
(五)、 填充函数
前面已经涉及到了用填充图样和填充色填充图形的问题,如调用pieslice()画扇区就要用填充图样与填充色来填充区域。那么怎样设置填充图样和填充色呢?我们只要简单地学习并练习一下就会掌握其方法。下面介绍用于设置填图样与填充色、建立用户自己的填充图样与填充封闭区域的几个常用函数。
76. setfillstyle() 设置填充图样和颜色函数
功能:setfillstyle()设置填充图样和颜色函数
功能: 函数setfillstyle()为各种图形函数设置填充图样和颜色。
用法: 函数调用方式为void setfillstyle(int pattern,int color);
说明: 参数pattern的值为填充图样,它们在头文件graphics.h中定义,详见表1-12所示。
参数color的值是填充色,它必须为当前显示模式所支持的有效值。
填充图样与填充色是独立的,可以是不同的值。
表1-12 填充图样
-------------------------------------------------------------------
填充图样符号名 取值 说明
-------------------------------------------------------------------
EMPTy_FILL 0 用背景色填充区域(空填)
SOLID_FILL 1 用实填充色填充(实填)
LINE_FILL 2 ----填充
LTSLASH_FILL 3 ///填充
SLASH_FILL 4 ///用粗线填充
BKSLASH_FILL 5 用粗线填充
LTBKSLASH_FILL 6 填充
HATCH_FILL 7 网格线填充
xHATCH_FILL 8 斜网格线填充
INTEREAVE_FILL 9 间隔点填充
WIDE_DOT_FILL 10 大间隔点填充
CLOSE_DOT_FILL 11 小间隔点填充
USER_FILL 12 用户定义图样填充
-------------------------------------------------------------------
除了EMPTy_FILL,所有填充图样都使用当前填充色,填充图样USER_FILL只有在用函数setfillpattern()已经建立一个用户定义的填充图样后才能使用。
此函数对应的头文件为graphics.h
返回值: 无
例: 下面的程序用HATCH_FILL填充一个矩形:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,mode,"");
setcolor(GREEN);
rectangle(80,200,200,300)
setfillstyle(HATCH_FILL,RED);
floodfill(160,240,GREEN);
getch();
restorecrtmode();
}
77. setfillpattern() 设置用户图样函数
功能: 函数setfillpattern() 设置用户的填充图样以供fllodfill(),fillpoly()填充函数等使用。
用法: 此函数调用方式为void setfillpattern(char *pattern,int color);
说明: 参数color设置填充图样的颜色。参数pattern指向一字符数组,该数组至少8个字节长,它定义了一个8像素*8像素的用户填充图样。例如:
char diamond[8]={0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00};
diamond为8个字节的数组,每个字节对应于填充图样中的8个像素,字节中的1位,画出一个由color设定颜色的像素,字节中的0位则不画。实际上,diamond数组定义了一个7*7的小钻石图样,右边和底部都留有一个像素的边缘。
调用setfillpattern()设置用户填充图样后,必须调用setfilstyle()函数,使USER_FILL值成为当前填充图样。
这个函数对应的头文件为graphics.h
返回值: 无
例:建立一个用户填充图样,并用它填充一个矩形:
#include<graphics.h>
void main()
{
int driver,mode;
static char p[8]={10,20,30,40,50,60,70,80};
driver=DETECT;
mode=0;
initgraph(&driver,mode,"");
setcolor(GREEN);
rectangle(80,200,220,300);
setfillpattern(p.RED);
floodfill(160,260,GREEN);
getch();
restorecrtmode();
}
78. floodfill() 填充闭域函数
功能: 函数floodfill()用当前填充图样和填充色填充一个由特定边界颜色(通常是当前绘图色)定义的有界封闭区域。
用法: 该函数调用方式为void floodfill(int x,int y,int bordercolor);
说明: 这里参数(x,y)为指定填充区域中的某点,如果点(x,y)在该填充区域之外,那么外部区域将被填充,但受图形视口边界的限制。如果直线定义的区域出现间断,那么将导致泄漏,即使很小的间断,也将导致泄漏。也就是说,间断将引起区域外被填充。
参数bordercolor为闭区域边界颜色,若可能的话,建议尽量用下面函数fillpoly()代替floodfill(),以便和将来的版本保持兼容。
如果出错,graphresult()函数将返回错误代码-7(flood填充内存不足)。
此函数对应的头文件为graphics.h
返回值: 无
例: 用floodfill() 函数填充一个具有交叉阴影线的品红色椭圆:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
ellipse(188,88,0,360,100,60);
setfillstyle(cHATCH_FILL,MAGENTA);
floodfill(188,88,WHITE);
getch();
restorecrtmode();
}
79. fillpoly() 填充多边形函数
功能: 函数fillpoly()用当前绘图色、线型及线宽画出给定点的多边形,然后用当前填充图样和填充色填充这个多边形。
用法: 此函数调用方式为void fillpoly(int pointnum,int *points);
说明: fillpoly()的调用形式与drawpoly()的一样,其参数含义相同。该函数中pointnum为所填充多边形的顶点数,points指向存放所有顶点坐标的整型数组。有时顶点数目是通过过计算sizeof(整型数组)除以两倍的sizeof(int)然后得到的,之所以除以两倍的sizeof(int)是因为每个顶点需要两个整型坐标。
注意,fillpoly()是通过连接起点和终点将图形封闭起来,然后填充被包围的区域。与floodfill()不同的是,fillpoly()所用的填充方法不依靠边界连续的轮廓来确定填充区域。这样间断的线型是允许的,并且可以很简单地填充多边形确定的区域,包括在新的边界范围内任何其它图形上重画。如果出错,graphresult()函数将返回错误代码-6(Scan填充内存不足)。
这个函数对应的头文件为graphics.h
返回值: 无
例:用红色间隔点填充一个正方形:
#include<graphics.h>
void main()
{
int driver,mode;
static int points[]={100,100,100,200,200,200,100,100};
driver=DETECT
mode=0;
initgraph(&driver,mode,"");
setfillstyle(INTERLEAVE_FILL,RED);
fillpoly(4,points);
getch();
restorecrtmode();
}
80. getfillsettings() 获取填充设置函数
功能: 函数getfillsettings()将当前填充图样值(符号名或等价值)和填充颜色值(符号名或等价值)填入fillsettingstyle型结构里,从而从该结构中获得当前填充设置(填充图样和填充色)。
用法: 这个函数调用方式为void getfillsettings(struct fillsettingstype *info);
说明: 函数里fillsettingstype 型结构定义如下:
struct fillsettingstype {
int pattern;
int color;
};
注意,结构中变量pattern只用于存取一个预先定义的填充图样值,而不是填充图样元素,填充图样及等价值在前面表1-12中已经列出。结构变量color用来存储填充颜色值,它是当前显示模式的有效颜色值之一。
getfillsettings()函数相应的头文件是graphics.h
返回值:返回当前填充图样和填充色的值,并装入info指向的结构里。
例: 下面的程序把当前填充图样和填充色的值写入fillinfo结构中:
struct fillsettingstype fillinfo;
getfillsettings(&fillinfo);
81. getfillpattern() 获取用户图样设置函数
功能: 函数getfillpattern()返回上一次调用setfillpattern()设置的用户定义的填充图样。
用法: 此函数调用方式为void getfillpattern(char *pattern);
说明: 函数一旦调用,就会把定义当前用户填充图样的8个字节填入pattern所指向的数组,该数组必须至少8字节长,用户图样以8个8位字节的模式排列,如果还没有调用setfillpattern()设置用户定义的填充图样,那么函数将填入数组元素的值全为0xff。
getfillpattern()函数对应的头文件为graphics.h
返回值: 返回用户定义填充图样的8个字节数据(注意不是填充图样元素),并存放在pattern指向的数组里。
例: 显示组成当前用户填充图样的各字节内容:
#include<graphics.h>
void main()
{
int driver,mode;
char fp[8];
int i;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
getfillpattern(fp);
for(i=0;i<8;i++) printf("%d",fp);
getch();
restorecrtmode();
}
(六)、图像函数
图像复制、擦除以及一般对屏幕图像的操作,这对应用程序是非常有用的,对动画制作是必不可少的。BC提供了以下几个图像操作函数。
82. imagesize() 图像存储大小函数
功能: 函数imagsize()返回存储一块屏幕图像所需的内存大小(即字节数)。
用法: 此函数调用方式为unsigned imagsize(int left,int top,int right,int bottom);
说明: 参数(left,top)为所定义的一块图像屏幕左上角,(right,bottom)为其右下角。
函数调用执行后,返回存储该块屏幕所需要的字节数。如果所需要字节数大于64KB,那么将返回-1。imagesize()函数一般与下面getimage()函数联用。
这个函数对应的头文件为graphics.h
返回值: 返回一块图像屏幕存储所需的字节数,如果大于64KB,则返回-1。
例: 确定左上角(10,10)与右下角(100,100)所定义的屏幕图像所需的字节数:
unsigned size;
size=imagesize(10,10,100,100);
83. getimage() 保存图像函数
功能: 函数getimage()保存左上角与右下角所定义的屏幕上像素图形到指定的内存区域。
用法: 该函数调用方式为void getimage(int left,int top,int right,int bottom,void *buf);
说明: 函数中参数(left,top)为要保存的图像屏幕的左上角,(right,bottom)为其右下角,buf指向保存图像的内存地址。调用getimage()保存屏幕图像,可用imagesize()函数确定保存图像所需字节数,再用malloc()函数分配存储图像的内存(内存分配必须小于64KB),还可以用下面函数putimage()输出getimage()保存的屏幕图像。
这个函数对应的头文件为graphics.h
返回值: 无
例: 把带有两对角线的矩形拷贝到屏幕其它位置上:
#include<garphics.h>
#include<stdlib.h>
#include<conio.h>
void main()
{
int driver,mode;
unsigned size;
void *buf;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
sector(15);
rectangle(20,20,200,200);
setcolor(RED);
line(20,20,200,200);
setcolor(GREEN);
line(20,200,200,20);
getch();
size=imagesize(20,20,200,200);
if(size!=-1){
buf=malloc(size);
if(buf){
getimage(20,20,200,200,buf);
putimage(100,100,buf,COPy_PUT);
putimage(300,50,buf,COPy_PUT);
}
}
outtext("press a key");
getch();
restorecrtmode();
}
84. putimage() 输出图像函数
功能: 函数putimage()将一个先前保存在内存中的图像输出到屏幕上。
用法: 此函数调用方式为void putimage(int left,int top,void *buf,int ops);
说明: 参数(left,top)为输出屏幕图像的左上角,即输出图像的起始位置。buf指向要输出的内存中图像。参数ops控制图像以何种方式输出到屏幕上。表1-13给出了图像输出方式。
表1-13 图像输出方式
--------------------------------------------------------------------
输出方式符号名 取值 含 义
--------------------------------------------------------------------
COPy_PUT 0 图像输出到屏幕上,取代原有图像
xOR_PUT 1 图像和原有像素作异或运算
OR_PUT 2 图像和原有像素作或运算
AND_PUT 3 图像和原有像素作与运算
NOT_PUT 4 把求反的位图像输出到屏幕上
--------------------------------------------------------------------
1) COPy_PUT输出方式
图像中每个像素都直接绘制到屏幕上,取代原有图像像素,包括空白的图像像素(背景)。完全空白的图像可以用来擦除其它图像或屏幕的一部分。但通常选择xOR_PUT输出方式擦除原有图像。
2)xOR_PUT输出方式
原有屏幕每个像素与相应的图像字节作“异或”运算,其结果画到屏幕上。当某一图像和屏幕上原有图像作“异或”运算时,屏幕显示的是两个图像的合成。若相同的图像作异或运算,将有效地擦除该图像,留下原始屏幕。这种输出方式,对动画制作是非常有用的。
3)OR_PUT输出方式
每个图像字节和相应的屏幕像素作“或”运算,再将结果画到屏幕上,这种输出方式也叫“两者取一”。记住,像素中的每位和图像中的每位作“或”运算,这样所得结果是背景和图像的彩色合成图像。
4)AND_PUT输出方式
选择AND_PUT图像输出方式时,屏幕像素和图像字节中都显示的位,运算后仍显示,例如,星图像中的空白背景擦除了方块轮廓以及填充色,只有星图像复盖着的方块留下,即运算后,显示两者相同的图像。
5)NOT_PUT输出方式
NOT_PUT输出方式,除了把图像的每位求反---图像中所有黑的像素(0000)变成了白色(1111),其它方面与COPy_PUT相同。背景图像被重画后将消失。
putimage()函数对应的头文件为garphics.h
返回值: 无
例: 下面的程序说明了imagesize(),getimage()和putimage()函数的调用方法:
#include<graphics.h>
#include<conio.h>
#include<stdlib.h>
void box(int ,int,int,int,int);
void main()
{
int driver,mode;
unsigned size;
void *buf;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
box(20,20,200,200,15);
setcolor(RED);
line(20,20,200,200);
setcolor(GREEN);
line(20,200,200,20);
getch();
size=imagesize(20,20,200,200);
if(size!=-1)
{
buf=malloc(size);
if(buf){
getimage(20,20,200,200,buf);
putimage(120,120,buf,COPy_PUT);
putimage(280,60,buf,COPy_PUT);
}
}
outtext("Press a key");
getch();
restorecrtmode)(;
}
void box(int startx,int starty,int endx,int endy,int color)
{
setcolor(color);
rectangle(startx,starty,endx,endy);
}
图像函数是对屏幕图像操作进行讨论的,但对屏幕图形同样适用。实际上,屏幕图形也是一种特定的屏幕图像,它可称为外形屏幕图像或称轮廓屏幕图像。因此图像与图形不必区分。
一、图形文本函数
85. outtext() 当前位置显示字符串函数
86. outtextxy() 在(x,y)处显示字符串函数
87. sprintf() 格式化输出函数
二、图形文本设置
88. settextstyle() 设置文本型式函数
89. settextjustify() 设置文本排齐函数
90. setusercharsize() 设置用户字符比例函数
91. gettextsettings() 获取文本设置函数
92. textheight() 文本高度函数
93. textwidth() 文本宽度函数
如果没有文本,图形也派不太多的用场。但是图形模式一旦设置,就无法进行常规文本显示。标号和文字信息只能用图形文本显示。图形文本显示与常规文本显示不同。例如,常规字符屏幕的位置其行列坐标表示已不再适用,这时单个字符可显示在屏幕上的任何位置。另外图形文本显示既可以水平显示,也可以垂直显示,字母大小也可以改变,同时可以提供几种不同的字型。总之,常规文本显示简单容易;图形文本显示复杂不易操作。所以,在C语言里提供了几个函数来简化操作,控制图形文本显示。
一、图形文本函数
在图形模式下,屏幕上显示字符串,可以用outtext(),outtextxy(),sprintf()。
85. outtext() 当前位置显示字符串函数
功能: 函数outtext() 在图形模式下用当前文本设置(字体、字符大小、文本显示方向及文本排齐方式)在当前位置显示一个字符串。
用法: 此函数调用方式为void outtext(char *string);
说明: 参数string指向要显示的字符串。
调用该函数 也可以根据需要事先设置当前绘图色,选择字体、字符大小、确定文本显示方向及水平垂直两个方向的文本排齐方式。
如果当前显示方向是水平的,那么当前光标位置CP会移动所显示字符的长度,否则CP不变;在图形模式下,光标不可见,但是即使是不可见光标,在屏幕上光标位置CP还是存在的。
这个函数对应的头文件是graphics.h
例: 使用outtext()函数的例子见86.outtextxy()函数的例子中。
86. outtextxy() 在(x,y)处显示字符串函数
功能:函数outtextxy() 在图形模式下屏幕坐标像素点(x,y)处显示一个字符串。
用法: 这个函数的调用方式为void outtextxy(int x,int y,char *string);
说明: 参数(x,y)给定要显示字符串的屏幕位置,string指向该字符串。调用此函数不影响当前光标位置,当然光标是不可见的。
该函数也要用当前绘图色、字体、字符大小、文本显示方向和水平垂直两个方向的文本排齐方式。
outtextxy()的对应头文件是graphics.h
返回值: 无
例: 下面的程序中调用了outtext()和outtextxy()两个函数:
#include<graphics.h>
void main()
{
int driver,mode;
int i;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
outtext("This is an example");
outtext("another line");
for(i=100;i<200;i+=8)
outtextxy(200,i,"hello");
getch();
restorecrtmode();
}
87. sprintf() 格式化输出函数
功能: 函数sprintf()用来作格式化的输出。
用法: 此函数调用方式为int sprintf(char *string,char *format,arg_list);
说明: 函数sprintf()的用法和printf()函数一样,只是sprintf()函数给出第一个参数string(一般为字符数组),然后再调用outtextxy()函数将串里的字符显示在屏幕上。arg_list为参数表,可有不定个数。通常在绘图方式下输出数字时可调用sprintf()函数将所要输出的格式送到第一个参数,然后显示输出。
如果没有文本,图形也派不太多的用场。但是图形模式一旦设置,就无法进行常规文本显示。标号和文官信息只能用图形文本显示。图形文本显示与常规文本显示不同。例如,常规字符屏幕的位置其行列坐标表示已不再适用,这时单个字符可显示在屏幕上的任何位置。另外图形文本显示既可以水平显示,也可以垂直显示,字母大小也可以改变,同时可以提 供几种不同的字型。总之,常规文本显示简单容易;图形文本显示复杂不易操作。所以,在C语言里提 供了几个函数来简化操作,控制图形文本显示。
二、图形文本设置
常规文本模式显示相当于在纸上打字,而图形文本模式显示更接近于排版印刷。这种增强性能的关键是改变字体及字符大小。选择不同的水平位置文本排齐,甚至可以在垂直方向而不是水平方向显示文本。这些都要调用文本设置函数来实现。
88. settextstyle() 设置文本型式函数
功能: 函数settextstyle() 设置图形文本当前字体、文本显示方向(水平显示或垂直显示)以及字符大小。
用法: 此函数调用方式为void settextstyle(int font,int direction,int charsize);
说明: 函数括号中,font为文本字体参数,direction为文本显示方向,charsize为字符大小参数。头部文件graphics中分别对它们进行了定义。表1-14所列为标准字体。
表1-14 图形文本标准字体
--------------------------------------------------------------------
字体符号名 等价值 含 义
--------------------------------------------------------------------
DEFAULT_FONT 0 8*8点阵字型(缺省字体)
TRIPLEx_FONT 1 笔划式三倍字型(三倍字体)
SMALL_FONT 2 笔划式小字型(小字体)
SANS_SERIF_FONT 3 笔划式字(Sanserif字体)
GOTHIC_FONT 4 笔划黑体字型(哥特体)
--------------------------------------------------------------------
在设置字体之前,被选字体的.CHR文件必须装在initgraph()中指定的driverpath(驱动程序路径)目录或子目录里。
缺省时图形文本显示方向为水平方向,但可以设置图形文本显示方向为垂直方向(逆时针转90度)。表1-15给出了这两个图形文本显示方向。
表 1-15 图形文本显示方向
------------------------------------------------------------
显示方向符号名 等价值 说 明
------------------------------------------------------------
HORIZ_DIR 0 从左到右显示(水平方向)
VERT_DIR 1 从底向上显示(垂直方向)
------------------------------------------------------------
在垂直显示时,文本字符串从底部向上显示,目前还没有现成的规定从上到下或从左到右的显示,但若需要也可设计。
对点阵字体,字符大小可以在0到10之间选择。对于笔划字体,charsize(字符大小参数)=0表示以缺省比例显示即4倍或由函数setusercharsize()设置的用户自定字符的比例放大显示。最大有效的charsize值为0。
如果有错误参数值传给函数settextstyle(),graphresult()函数将给出值-11(表示一般图形错误),当前的文本型式保持不变。
settextstyle()函数相应的头文件为graphics.h
返回值:无
例: 下面的程序中使用了settextstyle()函数,显示不同的文本字体和大小:
#include<graphics.h>
#include<conio.h>
void main()
{
int driver,mode;
mode=0;
initgraph(&driver,&mode,"");
outtext("Normal");
settextstyle(GOTHIC_FONT,HORIZ_DIR,2);
outtext("Gothic");
settextstyle(TRIPLEx_FONT,HORIZ_DIR,2);
outtext("Triplex");
settextstyle(SANS_SERIF_FONT,HORIZ_DIR,7);
outtext("Sans serif");
getch();
restorecrtmode();
}
89. settextjustify() 设置文本排齐函数
功能: 函数settextjustify() 设置水平方向和垂直方向的文本排齐方式。
用法: 该函数调用方式为void settextjustify(int horiz,int vert);
说明: 参数horiz,vert确定水平方向、垂直方向的文本排齐方式,其值如表1-16所示。
表 1-16 图形文本排列方式
---------------------------------------------------------------------------
水平方向排齐 等价值 垂直方向排齐 等价值
符号名 符号名
---------------------------------------------------------------------------
LEFT_TExT 0 BOTTOM_TExT 0
CENTER_TExT 1 CENTER_TExT 1
RIGHT_TExT 2 TOP_TExT 2
---------------------------------------------------------------------------
对于水平方向排齐,若取LEFT_TExT,则文本左边不敢当前位置CP对齐,向右显示文本字符串。若取CENTER_TExT,则文本字符串的中心与当前位置CP对准显示,若取RIGHT_TExT,则文本右边与当前位置CP对齐,向左显示文本字符串。至于垂直方向排齐BOTTOM_TExT,是文本字符串的底线与当前位置CP对准。CENTER_TExT是文本字符串的中线与CP对上,TOP_TExT是文本字符串的顶线过CP,缺省值为水平方向文本排齐方式LEFT_TExT以及垂直方向文本排齐方式TOP_TExT。
settextjustify()函数对应的头文件为graphics.h
例: 下面的程序语句使图形文本字符串靠右,即字符串右边紧靠当前位置排齐,并且其顶线过CP:
settextjustify(RIGHT_TExT,TOP_TExT);
90. setusercharsize() 设置用户字符比例函数
功能: 函数setusercharsize() 可以让用户自定义笔划字体的字符比例,但对于缺省字体的字符无效,因为缺省字体是由硬件定义的8*8点阵字体。
用法:此函数调用方式为void setusercharsize(int xmul,int xdiv,int ymul,int ydiv);
说明: 参数xmul/xdiv为设置的字符宽度比例,参数ymul/ydiv为设置的字符高度比例。该函数调用后,屏幕上显示的字符宽为其缺省值8个像素乘以宽度比例,高为其缺省值8个像素乘以高度比例。注意,只有在调用settextstyle()函数设置参数charsize为0 时,字符调节参数才有效。若要显示高度比例为3,宽是高的2倍的字符,可以用下述方法调用函数setuserchrsize():
xmul=6;xdiv=1;
ymul=3;ydiv=1;
setusercharsize(xmul,xdiv,ymul,ydiv);
这里产生的字符为12个像素宽,48个像素高。
setusercharsize()函数对应的头文件为graphics.h
返回值: 无
例: 显示大号字符文字:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
settextstyle(TRIPLEx_FONT,HORIZ_DIR,0);
setusercharsize(5,1,5,1);
outtext("big");
getch();
restorecrtmode();
}
91. gettextsettings() 获取文本设置函数
功能: 函数gettextsettings() 将当前字体、显示方向、字符大小和水平垂直方向文本排齐方式等设置值填入textsettingstype型结构里,从而可从中获取文本信息。
用法: gettextsettings() 函数的调用方式为void gettextsettings(struct textsettingstype *info);
说明: 函数中textsettingdtype型结构在头部文件graphics.h中定义如下:
strcut textsettingstype {
int font; // 字体
int direction; // 水平或垂直方向
int charsize; // 字符大小
int horiz; // 水平排齐方式
int vert; // 垂直排齐方式
};
结构中成员font的取值为下列各值之一:
值 字体
-------------------------------
0 缺省字体
1 三倍字体
2 小字体
3 SansSerif字体
4 哥特体
-------------------------------
变量charsize的值是确定输出字符大小的系数,在0到10之间选取。
direction方向变量可设置为水平显示HORIZ_DIR(缺省值),或设置为垂直显示VERT_DIR。horiz和vert为文本排齐方式变量,其值是下列中的一个:
符号名 值 说 明
---------------------------------------------------------------
LEFT_TExT 0 CP(当前位置在左边)
CENTER_TExT 1 CP在中心
RIGHT_TExT 2 CP在右边
BOTTOM_TExT 3 CP在底部
TOP_TExT 4 CP在顶部
---------------------------------------------------------------
另见settextjustify()函数的说明部分。
这个函数对应的头文件为graphics.h
返回值: 返回当前文本设置信息并装入info指向的结构里,然后便可以从该结构中获得文本设置各值。
例: 读入当前文本设置值。
struct textsettingstype ts;
gettextsettings(&ts);
92. textheight() 文本高度函数
功能: 函数textheight() 返回字符串的高度。
用法: 函数调用方式为int textheight(char *string);
说明: 参数string指向字符串.函数textheight()按当前字体、字符大小、比例因子和文本方向,计算出字符串高度的像素数。这可以是当前单字符的高度,也可以是当前整个字符串的高度值。
此函数对应的头文件为graphics.h
返回值: 返回字符串高度像素数。
例: 显示数字字符的高度:
#include<graphics.h>
void main()
{
int driver,mode;
driver=0;
mode=0;
initgraph(&driver,&mode,"");
printf(height: %d",textheight("8"));
getch();
restorecrtmode();
}
93. textwidth() 文本宽度函数
功能: 函数textwidth() 返回字符串的宽度。
用法: 此函数调用方式为int textwidth(char *string);
说明: 参数string指向字符串。函数textwidth()按当前字体、字符大小、比例因子和文本方向,计算出字符串宽度的像素数。这既可以是单字符的宽度,又可以是整个字符串的宽度,并且通常是整个字符串的宽度值。
这个函数对应的头文件是graphics.h
返回值: 返回字符串宽度像素数。
例: 显示字符串hello的宽度:
#include<graphics.h>
void main()
{
int driver,mode;
driver=DETECT;
mode=0;
initgraph(&driver,&mode,"");
printf("width: %d",textwidth("hello"));
getch();
restorecrtmode();
}
第三节 二维裁剪
一、线段裁剪
二、多边形裁剪
第三节 二维裁剪
在二维图形的绘制或显示处理中,有时需要给出或显示某一部分原始图形。这可在适当位置按一定边界范围定义一个矩形区域(即窗口),使窗口内图形为所需部分,将其保留下来作为绘制或显示之用,而窗口边界以外的图形则予以舍弃。这种对二维原始图形的处理称为二维裁剪。
二维裁剪处理主要是判断图形元素是否在所开的窗口内,若在内则进一步求出窗口内的那一部分。也就是说裁剪处理工作有两点:第一是窗口内外的判断;第二是计算图形元素与窗口边界的交点。
在定义一个窗口时,一般规定窗口为矩形框。它在用户坐标系中的位置和大小用窗口对角点坐标或右下角点坐标(x1,y1)和右上角点坐标(x2,y2)来表示,有时也可用窗口原点(左下角点或右上角点)和窗口边长来表示。在某些情况下,用户也可以用圆心和半径来定图形窗口,或定义其它窗口。
在实际应用中,往往需要观察某一图形的各个细部,或切产生不同比例的显示图形,这些都需要对原图形作二维处理。裁剪处理是把每个图形元素分成窗口内的与窗口外两部分,舍弃窗口外部分。虽然对不同的图形元素(如点、线段、多边形等)有不同的裁剪算法,但它们的原理都是一致的。都是一对简单的不等式,由这对不等式来确定图形上的点(x,y)是否位于窗口内。在选定窗口的情况下,如窗口的四条边线是x=x1,x=x2,y=y1,y=y2时,不等式为
x1≤x≤x2
y1≤y≤y2
根据此式对图形进行逐点裁剪,不满足其中任何一个不等式的点就不在窗口内,应舍弃。显然这种算法效率很低。因此要另外设计对较大图形是行裁剪的算法,如对线段、多边形进行裁剪的算法,下面分别介绍。
一、线段裁剪
裁剪处理的关键是如何去掉窗口外的图形,这要设计出相应的算法。在线段裁剪算法中,需要检查线段相对于窗口的位置关系。对整个位于窗口内的线段须全部保留,对整个位于窗口外的线段要全部予以舍弃。对于部分位于窗口内而其余部分位于窗口外的线段 则须计算出该线段与窗口边的交点作为线段的分段点,保留位于窗口内的那部分线段,舍弃其余部分线段。一般线段两端点相对于窗口的位置有下面几种情况:
1、两端点均在窗口外同一侧位置。如图2-6中线段CD,这时线段全部位于窗口之外,故整个线段舍弃。
2、两端点均在窗口内,如图2-6中线段MN,显然整个线段位于窗口内,应全部保留。
3、两端点线段中,一点在窗口内,另一点在窗口外,如图2-6中线段PQ,在这种情况应计算出线段PQ与窗口边的交点T,保留窗口内部分线段TQ,舍弃其余部分线段PT。
4、两端点均不在窗口内,但又不处于 边界外同一侧位置,如图2-6中线段AB和线段EF,这时线段可能穿过窗口(如线段AB)也可能全部位于窗口之外(如线段EF),因此需要根据线段与窗口边界的交点来判断。若线段与窗口边线的交点中有两个交点处于窗口上,则此两交点间线段位于窗口内,予以保留,线段的其余部分位于窗口外,应舍弃;若线段与窗口边界的所有交点均在之外,则整个线段位于窗口外,应予全部舍弃。
下面介绍线段裁剪算法(编码裁剪法)。
由上面线段相对于窗口的位置的几种情况讨论可以得知,有些线段被窗口边界切割后会产生一条以上的窗口外的线段,而窗口内的线段却只有一条。这一点很重要,它意味着要确定窗口内的线段,只要计算出它位于窗口内的两个端点。丹科恩和伊凡.瑟萨兰德就根据这一思路设计出了线段裁剪的算法。这种算法分为两步:第一步先确定该线段是否整个位于窗口内或全部位于窗口外,若属于这两种情况,则全部保留或全部舍弃;第二步对不属于第一步那两种情况的线段,则被窗口某一边界线分成两部分,再对每一部分进行第一步。具本这两步留舍测试如下进行:延长窗口各边界,将窗口及其周围共划分为九个区域,中央就是所要裁剪的区域。每个区域各用一个四位二进制数组成的代码(即代码中每一位分别为0或1)来表示,如图2-7所示。
当线的一端点位于某一区域时,便将该区域的代码赋予端点。然后根据线从而段两端点代码就能很方便地判断出线段相对于窗口的位置关系,并决定对该线段如何进行裁剪。四位代码中每位(位的顺序由右向左排序)代码的意义如下:
第一位,点在窗口左边界线之左为1,否则为0;
第二位,点在窗口右边界线之右为1,否则为0;
第三位,点在窗口底边界线之下为1,否则为0;
第四位,点在窗口顶边界线之上为1,否则为0。
对线段进行测试时,首先对全部保留和全部舍弃线段这两种情况进行判断,即
1、当线段两端点的四位代码全由零组成时,则表示两端点均在窗口内,要全部保留该线段。
2、当线段的四位代码逻辑乘不等于零时,则表示两个端点的代码中有一相同位,同时为1;若线段两个端点在侣边界线外的同侧位置,则整个线段在窗口之外,应予全部舍弃。如图2-6中各线段端点代码(或称编码)逻辑乘如表2-1所示。
表 2-1 线段端点代码及其逻辑
----------------------------------------------------------------------
线段 端点代码 逻辑乘 注释
(见图2-6) (见图2-7中代码规则) (窗口内为可见)
----------------------------------------------------------------------
AB 0 0 0 1 0 0 1 0 0 0 0 0 部分可见
CD 0 1 0 0 0 1 0 0 0 1 0 0 不可见
EF 0 0 0 1 1 0 0 0 0 0 0 0 不可见
MN 0 0 0 0 0 0 0 0 0 0 0 0 可 见
PQ 0 0 1 0 0 0 0 0 0 0 0 0 部分可见
----------------------------------------------------------------------
由表2-1可得知,当线段两端点逻辑乘非零时,则线段不可见。但当线段两端点逻辑乘为零时,则有三种情形:可见,部分可见与不可见,因此这时不需要对端两端点代码分别进行检查。
如果线段不能通过上述两种测试判断为保留或舍弃,则必须求出线段与窗口边界线的交点,即分割 线段 ,舍弃在窗口外同侧的部分线段,对留下的线段重复进行上述两种情况的判断,直到留下的线段符合上述两种情况之一为止。
二、多边形裁剪
多边形裁剪比线段裁剪要复杂许多。多边形裁剪需要解决两个问题:一是一个完整封闭的多边形经剪裁后不再是封闭的,需要用窗口边界的适当部分来封闭它;二是边界线段的边接,不适当的连接会产生错误。另外如果对多边形相对于窗口的四条边同时进行裁剪,那么很难算出应该使用窗口的哪些边界线段来封闭图形。但相对于窗口的一条边界线来裁剪多边形就比较容易,并由此可提出多边形裁剪算法。
下面介绍多边形裁剪算法(逐边裁剪法)。
伊凡.瑟萨兰德和格雷霍奇曼1974年对多边形裁剪提 出了逐边裁剪算法。他们的思路是,把多边形裁剪这样一个整体问题分割成一系列简单问题,这些简单问题解决了,对整体也解决了。具体算法是:把整个多边形先相对于窗口的第一条边界线进行裁剪,形成一个新的多边形;然后再把这个新的多边形相对于窗口的第二条边界线进行裁剪、再次形成一个新的多边形;接着用窗口的第三条边、第四条边依次进行如此剪裁,最后形成一个整个多边形经过窗口的四条边界线裁剪后的多边形。这个多边形裁剪过程如图2-8所示。
这个算法看起来好像要很大的内存保留中间数据,其实不然,它可以采用递归方式调用同一算法,整个裁剪过程由四级同样的算法组成。每一级相对于窗口的四条边界线之一来剪裁,第一级输出的顶点传送给第二级(即把多边形每个顶点相对于第一条边界线裁剪,所形成的多边形顶点作为下一步裁剪过程输入),第二级的顶点输出传送给第三级,依此类推,最后一级产生的顶点就构成经过裁剪的多边形。具体实现采用一个数组存放原始多边形的顶点坐标,再设置一个待裁剪多边形顶点坐标数组,用来存放经某条窗口边界线裁剪后所生成的顶点坐标,不妨把这个数组称为新多边形数组,最后新多边形数组存放的是经所有窗口边界裁剪完毕而得到的结果多边形的顶点坐标。
设与多边形的顶点为P1、P2、P3、......Pn,多边形的各条边线分别为顶点P1与P2、P2与P3、......、Pn与P1的连线,其中Pn与P1的连线为多边形的封闭边。多边形在裁剪后应得到一个或几个新的多边形,其顶点为Q1、Q2、Q3......、Qn, 主要任务就是求得这些新的顶点。其过程是,首先依次按照窗口的一条边界线L对多边形的顶点Pi(i=1,2,3...,n)进行检查。若顶点在边界L以内,则保留该顶点作为裁剪后新的顶点,反之则予以舍弃。同时对于顶点Pi是否与前一顶点Pi-1处于窗口边解甲归田线L的同侧位置,还须进行检查。若它们分别位于窗口边蜀线的两侧,则应计算边线Pi-1Pi与窗口边线L的交点,并将交点保留下来作为裁剪后新的顶点输出。显然对于多边形的第一个顶点P1来说,上述后一顶检查无意义可以省略。当检查最末一个顶点Pn时,除了进行上述检查外,还须对多边形的封闭边PnP1进行检查。若封闭边PnP1与窗口边界线L相交,则应计算这一点并予以保留。这样通过以上检查便保留并输出各顶点Q1、Q2、Q3、......Qn,在这些顶点之间依次联成边线,即可得到裁剪后新的多边形。
实例:一个零件图形的绘制
有一个零件图,如下:
对图3-1中的零件图形,如何根据它所标注的尺寸,按照适当的顺序有步聚地画出该图形,这首先要分析此零件图形的几何关系,了解构成这个图形各线段的性质,才能顺利地绘出此图形。线段(直线或圆弧)在零件图形中分为三类,即已知线段、中间线段和连接线段。以圆弧为例,按几何原理,已知圆心的两个位置尺寸与半径尺寸便可画出圆。因此图形中,已知这三个尺寸的圆弧称为已知圆弧,画图时应该最先画出。凡已知其中二个尺寸的圆弧称为中间圆弧。凡只已知一个尺寸(一般是圆弧半径)的圆弧称为连接圆弧。中间圆弧和连接圆弧都缺省圆心的位置尺寸,它的几何位置是根据相切的条件来确定的。因此画圆弧的顺序为:先画已知圆弧,再画中间圆弧,最后画连接圆弧。
本零件图形是对称图形,三个小圆均匀分布在圆周中心线上,φ10,φ25,φ50和R10都是已知圆弧,R8为连接圆弧,φ50是已知圆弧的端点和R10已知圆弧的端点与连接圆弧的端点相切,从而构成整个图形。
写出算法:
知道了图形的几何关系后,就是怎样用绘图算式或关系式将图形几何关系表示出来,这也就是所要写出的绘图算法,包括算式或关系式中的变量和参数说明。
现在讨论此零件图形的绘图算法。
1. 建立坐标系
以基准为轴线,原点定在中心。
2. 确定贺半径关系
由于所编程序要绘制一类零件图形(这实际上就是参数化绘图),所以在绘图算法公式中φ25圆(以后称内圆)、φ50圆(外圆)和R10圆(凸圆)的半径设计成参变量,其值由用户输入。
所有圆半径的关系如下:
Ri > 0
R0 > Ri
Rc > 0
Rp = Ri + ( Rc - Ri ) / 5
Rs = Rc / 2
Rj = 4 * Rc / 5
式中Ri为内圆半径,R0为外圆半径,Rc为凸圆半径,Rp为点画圆半径,Rs为三个小圆半径,Rj为连接圆半径。
3. 算出φ10圆圆心
设三个φ10圆圆心位置坐标分别为C1(u1,v1),C2(u2,v2),C3(u3,v3),则由零件图上可得计算它们的值的公式为
右边小圆C1:
u1=[Ri+(R0-Ri)/5]cos(-30o)
v1=[Ri+(Ro-Ri)/5]sin(-30o)
上边小圆C2:
u2=[Ri+(Ro-Ri)/5]cos(90o)
v2=[Ri+(Ro-Ri)/5]sin(90o)
左边小圆C3:
u3=[Ri+(Ro-Ri)/5]cos(210o)
v3=[Ri+(Ro-Ri)/5]sin(210o)
式中Ri,Ro含义同前面。
4. 求连接圆弧圆心
设六个连接圆弧的圆心位置坐标分别为L1(x1,y1),L2(x2,y2),L3(x3,y3),L4(x4,y4),L5(x5,y5),L6(x6,y6),则利用连心线长度与距离公式可列出求这六个连接圆弧圆心坐标的六个方程组,进而分别求解可得到圆心坐标的表达式。
这样,连接圆弧L1的议程组是
(x1)2+(y1)2=(Ro-4/5Rc)2
(x1-u1)2+(y1-v1)2=(9/5Rc)2
记 A=(Ro)2+8Ro*Rc/5+16(Rc)2/25
B=(Ro)2+8Rc*Rc/5-13(Rc)2/5
D1=(u1)2+(v1)2
式中Rc为R10圆的半径,Ro为φ50圆的半径。
则方程组成为
(x1)2+(y1)2=A
2u1*x1+2v1*y1=B+D1
解此方程组,有
D1(y1)2-v1(B+D1)*y1+[(B+D1)/2]2-A(u1)2=0
上式中令
a=D1
b=-v1(B+D1)
c=[(B+D1)/2]2-A(u1)2
便成为
a(y1)2+by1+c=0
再由求根公式即得
b2-4ac=(u1)2[4AD1-(B+D1)2]
方程的根为
v1(B+D1)±(u1)2[4AD1-(B+D1)2]
y1'= -----------------------------
2D1
将y1'代入原方程组便得另外的根
x1'=±(A-(y1')2)1/2
于是连接圆弧L1的圆心坐标表达式为
v1(B+D1)±(u1)2[4AD1-(B+D1)2]
y1'= -------------------------------
2D1
x1'=±(A-(y1')2)1/2
连接圆弧L2的方程组与上面的一样,因为都是关于同样的条件建立方程组,即利用到右边小圆心的连心距离建立方程组,因此上面的两组解有一组是L2连接圆弧的圆心位置坐标。
同样方法可得连接圆弧L3(L1类同)的方程组为
(x3)2+(y3)2=A
2u2*x3+2v2*y3=B+D2
式中D2=(u2)2+(v2)2 A,B 同上
方程组解即L3(L4类同)连接圆弧的圆心坐标位置为
v2(B+D2)±(u2)2[4AD2-(B+D2)2]
y3'= -------------------------------
2D2
x3'=±(A-(y3')2)1/2
比较一下L1(或L2)与L3(或L4)的方程组就会发现,只需将连接圆弧L3(或L4)的方程组中的小圆圆心坐标换成左边小圆圆心坐标,连接圆弧圆心坐标换成L5(或L6)连接圆弧的圆心位置坐标,常数D2也作相应变化便得到连接圆弧L5(L6类同)的方程组
(x5)2+(y5)2=A
2u3*x3+2v3*y5=B+D3
式中D3=(u3)2+(v3)2 A,B 同上
解该方程组得到L5(L6类同)连接圆弧的圆心坐标为
v3(B+D3)±(u3)2[4AD3-(B+D3)2]
y5'= -------------------------------
2D3
x5'=±(A-(y5')2)1/2
5.计算连接圆弧切点
求连接圆弧切点最简便的方法是用定百分比来求解。由图3-1可知,连接圆民外圆的切点为两圆连心线的定百分比,其定比值为λo=Ri/Ro,连接圆弧与凸圆的切点也是两圆连心线的定百分比,其定比值为λc=Rj/Rc,式中Rj,Ro,Rc是相应的圆半径。这样由定比分点计算公式,便可求得加心线上分点也即连接圆弧切点的坐 。
设连接圆弧L1,L2,L3,L4,L5,L6分别与各凸圆的切点为(cx1,cy1),(cx2,cy2),(cx3,cy3),(cx4,cy4),(cx5,cy5),(cx6,cy6),连接圆弧L1,L2,L3,L4,L5,L6与外圆的切点分别为(ox1,oy1),(ox2,oy2),(ox3,oy3),(ox4,oy4),(ox5,oy5),(ox6,oy6)。
已知三凸圆弧圆心坐标分别为(u1,v1),(u2,v2),(u3,v3),六连接圆弧圆心坐标分别为(x1',y1'),(x2',y2'),(x3',y3'),(x4',y4'),(x5,y5'),和(x6',y6')。
根据定比分点计算公式,可得连接圆弧L1与右边凸圆的切点坐标为
式中 λo=Rj/Ro
λc=Rj/Rc
Rj,Ro,Rc 是相应的圆弧半径
至此,求得了所有连接圆弧切点的坐标
(四)、编写绘图程序
在编写绘图程序前,最好先画出要编写程序的流程框图,然后按照框图内容所描述的计算,用程序语言来实现。
第一框 输入数据,用下面一个函数实现:
void Enterdata()
{
clrscr();
gotoxy(1,6);
printf("Enter the radius of the circles.n");
gotoxy(1,8);
printf(Enter in_circle radius(>=12.5):n");
scanf("%f",&Ri);
printf("Enter out_circle radius(>=25.0):n");
scanf(%f",&Ro);
printf("Enter convex_circle radius(=10.0):n");
scanf("%f",&Rc);
}
第二框画基准线与圆心线,可由下面的函数完成:
void Base_Center_Line()
{
flost dash_R;
desh_R=(4*Ro+Ri)/5; // 三个小圆圆心所在的点划圆半径
u1=((4*Ro+Ri)/5)*cos(-30*0.017453); // 确定三个小圆圆心坐标
v1=((4*Ro+Ri)/5)*sin(-30*0.017453);
u2=0.0; // ((4*Ro+Ri)/5)*cos(90*0.017453)
v2=((4*Ro+Ri)/5); // ((4*Ro+Ri)/5)*sin(90*0.017453)
u3=((4*Ro+Ri)/5)*cos(210*0.017453);
v3=((4*Ro+Ri)/5)*sin(210*0.017453);
line(mmaxx-Ro-Rc,mmaxy,mmaxx-(Ro+Rc)/2,mmaxy; // 画基准线
line(mmaxx-(Ro+Rc)/2+5,mmaxy,mmaxx-(Ro+Rc)/2+5,mmaxy);
line(mmaxx-(Ro+Rc)/2+10,mmaxy,mmaxx-(Ro+Rc)/2,mmaxy);
line(mmaxx+(Ro+Rc)/2+5,mmaxy,mmaxx-(Ro+Rc)/2+5,mmaxy);
line(mmaxx+(Ro+Rc)/2+10,mmaxy,mmaxx+Ro+Rc,mmaxy);
line(mmaxx,mmaxy+Ro+Rc,mmaxx,mmaxy+(Ro+Rc)/2+10);
line(mmaxx,mmaxy+(Ro+Rc)/2+5,mmaxx,mmaxy+(Ro+Rc)/2+5);
line(mmaxx,mmaxy+(Ro+Rc)/2,mmaxx,mmaxy-(Ro+Rc)/2+10);
line(mmaxx,mmaxy-(Ro+Rc)/2+5,mmaxx,mmaxy-(Ro+Rc)/2+5);
line(mmaxx,mmaxy-(Ro+Rc)/2,mmaxx,mmaxy-Ro-Rc);
arc(mmaxx,mmaxy,0,25,desh_R); // 画点划圆
arc(mmaxx,mmaxy,28,29,desh_R); // 画点划圆
arc(mmaxx,mmaxy,32,110,desh_R); // 画点划圆
arc(mmaxx,mmaxy,113,114,desh_R); // 画点划圆
arc(mmaxx,mmaxy,117,185,desh_R); // 画点划圆
arc(mmaxx,mmaxy,187,188,desh_R); // 画点划圆
arc(mmaxx,mmaxy,191,255,desh_R); // 画点划圆
arc(mmaxx,mmaxy,258,259,desh_R); // 画点划圆
arc(mmaxx,mmaxy,262,300,desh_R); // 画点划圆
arc(mmaxx,mmaxy,303,304,desh_R); // 画点划圆
arc(mmaxx,mmaxy,307,360,desh_R); // 画点划圆
}
第三个框 画已知圆的程序
void Known_Circle()
{
circle(mmaxx,mmaxy,Ri);
circle(mmaxx+u1,mmaxy-v1,Rc/2);
circle(mmaxx+u2,mmaxy-v2,Rc/2);
circle(mmaxx+u3,mmaxy-v3,Rc/2);
}
第四个框计算连接圆弧圆心,其程序也可作为一个函数如下:
void Link_Arc_Center()
{
float A,B,D1,D2,D3,B2_4AC1,B2_4AC2,B2_4AC3;
float BD1,BD2,BD3,Root1,Root2,Root3,temp;
A=Ro*Ro+8*Ro*Rc/5+16*Rc*Rc/25;
B=Ro*Ro+8*Ro*Rc/5-13*Rc*Rc/5;
D1=u1*u1+v1*v1; // D1为计算连接圆弧1与2圆心坐标需要的值,须先算出
D2=u2*u2+v2*v2; // D2为计算连接圆弧3与4圆心坐标需要的值,须先算出
D3=u3*u3+v3*v3; // D3为计算连接圆弧5与6圆心坐标需要的值,须先算出
// 下面几行计算都是为计算连接圆弧圆心坐标值做准备
BD1=B+D1
BD2=B+D2;
BD3=B+D3;
B2_4AC1=u1*u1*(4*A*D1)-BD1*BD1);
B2_4AC2=u2*u2*(4*A*D2)-BD2*BD2);
B2_4AC3=u3*u3*(4*A*D3)-BD3*BD3);
Root1=sqrt(B2_4AC1);
Root2=sqrt(B2_4AC2);
Root3=sqrt(B2_4AC3);
y1=(v1*BD1-Root1)/(2*D1); // 根据圆心坐标所处象限位置,选取正负号
// 连接圆弧1圆心y坐标值
temp=A-y1*y1;
x1=sqrt(temp); // 连接圆弧1圆心x坐标值
y2=(v1*BD1+Root1)/(2*D1); // 连接圆弧2圆心y坐标值
temp=A-y2*y2;
x2=sqrt(temp); // 连接圆弧2圆心x坐标值
y3=(v2*BD2+Root2)/(2*D2); // ±Root2=0
// 连接圆弧3圆心y坐标值
temp=A-y3*y3;
x3=sqrt(temp); // 连接圆弧3圆心x坐标值
y4=(v2*BD2+Root2)/(2*D2); // ±Root2=0
// 连接圆弧4圆心y坐标值
x4=-sqrt(A-y4*y4); // 连接圆弧4圆心x坐标值
y5=(v3*BD3+Root3)/(2*D3); // 连接圆弧5圆心y坐标值
x5=-sqrt(A-y5*y5); // 连接圆弧5圆心x坐标值
y6=(v3*BD3-Root3)/(2*D3); // 连接圆弧6圆心y坐标值
x6=-sqrt(A-y6*y6); // 连接圆弧6圆心x坐标值
}
第五个框求连接圆弧切点,其程序作为一个函数:
void Tangent_Point(){
float Rj,Lc,Lo;
Rj=4*Rc/5;
Lc=4.0/5.0; // =Rj/Rc
Lo=Rj/Rc;
cx1=(x1+Lc*u1)/(1+Lc); // 连接圆弧L1与右边凸圆的切点坐标
cy1=(y1+Lc*v1)/(1+Lc);
cx2=(x2+Lc*u1)/(1+Lc); // 连接圆弧L2与右边凸圆的切点坐标
cy2=(y2+Lc*v1)/(1+Lc);
cx3=(x3+Lc*u2)/(1+Lc); // 连接圆弧L3与上边凸圆的切点坐标
cy3=(y3+Lc*v2)/(1+Lc);
cx4=(x4+Lc*u2)/(1+Lc); // 连接圆弧L4与上边凸圆的切点坐标
cy4=(y4+Lc*v2)/(1+Lc);
cx5=(x5+Lc*u3)/(1+Lc); // 连接圆弧L5与左边凸圆的切点坐标
cy5=(y5+Lc*v3)/(1+Lc);
cx6=(x6+Lc*u3)/(1+Lc); // 连接圆弧L6与左边凸圆的切点坐标
cy6=(y6+Lc*v3)/(1+Lc);
ox1=(x1+Lo*0.0)/(1+Lo); // 连接圆弧L1与外圆的切点坐标
oy1=(y1+Lo*0.0)/(1+Lo);
ox2=(x2+Lo*0.0)/(1+Lo); // 连接圆弧L2与外圆的切点坐标
oy2=(y2+Lo*0.0)/(1+Lo);
ox3=(x3+Lo*0.0)/(1+Lo); // 连接圆弧L3与外圆的切点坐标
oy3=(y3+Lo*0.0)/(1+Lo);
ox4=(x4+Lo*0.0)/(1+Lo); // 连接圆弧L4与外圆的切点坐标
oy4=(y4+Lo*0.0)/(1+Lo);
ox5=(x5+Lo*0.0)/(1+Lo); // 连接圆弧L5与外圆的切点坐标
oy5=(y5+Lo*0.0)/(1+Lo);
ox6=(x6+Lo*0.0)/(1+Lo); // 连接圆弧L6与外圆的切点坐标
oy6=(y6+Lo*0.0)/(1+Lo);
}
最后一个框 画外圆弧、凸圆弧与连接圆弧,相应的程序为下面两个函数。
C语言中没有提供直接用圆心与圆弧端点坐标画圆弧的函数,下面函数Myarc()就可以实现这一功能,即直接用圆心、圆弧两端点坐标调用函数Myarc()画圆弧。
void Myarc(float ctx,float cty,float startx,float starty,float endx,float endy,float R)
{
float sx,sy,ex,ey,sangle,eangle;
sx=startx-ctx;
sy=starty-cty;
ex=endx-ctx;
ey=endy-cty;
if(sx!=0.0)
{
// θ=arctg y/x, (x>0.0)
// θ=arctg y/x+π,(x<0.0)
if(sx>0.00)sangle=atan(sy/sx); // 将起点转化成起始角
if(sx<0.0)sangle=atan(sy/sx)+3.1415926; // 将起点转化成起始角
}
else
{
if(sy>0.0)sangle=3.1415926/2; // 将起点转化成起始角
if(sy<0.0)sangle=3*3.1415926/2; // 将起点转化成起始角
}
if(ex!=0.0)
{
if(ex>0.0)eangle=atan(ey/ex); // 将终点转化成终止角
if(ex<0.0)eangle=atan(ey/ex)+3.1415926; // 将终点转化成终止角
}
else
{
if(ey>0.0)eangle=3.1415926/2; // 将终点转化成终止角
if(ey<0.0)eangle=3*3.1415926/2; // 将终点转化成终止角
}
sangle=sangle/0.017453; // 1=1o/0.017453
eangle=eangle/0.017453;
arc(mmaxx+ctx,mmaxy-cty,sangle,eangle,R); // 画出圆弧
}
void Out_Link_Arc()
{
float Rj;
Rj=4*Rc/5;
Myarc(u1,v1,cx1,cy1,cx2,cy2,Rc);
// 用凸圆弧1圆心、圆弧两端坐标和半径画出凸圆弧1,其它圆弧的绘制类同。
Myarc(x2,y2,ox2,oy2,cx2,cy2,Rj);
Myarc(0.0,0.0,ox2,oy2,ox3,oy3,Ro);
Myarc(x3,y3,cx3,cy3,ox3,oy3,Rj);
Myarc(u2,v2,cx3,cy3,cx4,cy4,Rc);
Myarc(x4,y4,ox4,oy4,cx4,cy4,Rj);
Myarc(0.0,0.0,ox4,oy4,ox5,oy5,Ro);
Myarc(x5,y5,cx5,cy5,ox5,oy5,Rj);
Myarc(u3,v3,cx5,cy5,cx6,cy6,Rc);
Myarc(x6,y6,ox6,oy6,cx6,cy6,Rj);
Myarc(0.0,0.0,ox6,oy6,ox1,oy1,Ro);
Myarc(x1,y1,cx1,cy1,ox1,oy1,Rj);
}
注意这里画圆弧不能直接用C语言中的画圆弧函数arc(),要把圆弧的两端切点即起点与终点转换成起始角与终止角后才能调用它。将圆弧两端点化成起始角与结束角度可通过直角坐标与极坐标的变换关系式来完成。具本转换过程见上面函数Myarc()中程序内容。
六个框的程序编写完后,再加上头文件、全局变量的说明、图形模式初始化函数和主函数就构成画此零件图的整个程序,见后面的程序。本程序运行时,需要用户按提示输入内圆、外圆和凸圆的半径(程序提示中的参数值相应程序图3-1中的图形)。用户可输入不同的参数值,绘出不同大小的同类图形。
// 1. 源程序 Example.c
#include<stdio.h>
#include<graphics.h>
#include<math.h>
#include<conio.h>
#include<stdlib.h>
float Ri,Ro,Rc,u1,v1,u2,v2,u3,v3,mmaxx,mmaxy;
float x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6;
float cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4,cx5,cy5,cx6,cy6,ox1,oy1,ox2,oy2,
ox3,oy3,ox4,oy4,ox5,oy5,ox6,oy6;
// 变量说明:Ri为内圆半径,Ro为外圆半径,Rc为凸圆半径,u1,v1,u2,v2,u3,v3分别为三个φ10圆
// 圆心位置坐标,x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6分别为六个连接圆弧的圆心位置坐标。
// cx1,cy1,cx2,cy2,cx3,cy3,cx4,cy4,cx5,cy5,cx6,cy6分另为连接圆弧与凸圆的切点坐标。
// ox1,oy1,ox2,oy2,ox3,oy3,ox4,oy4,ox5,oy5,ox6,oy6分别为连接圆弧与外圆的切点。
void EnterData() // 输入内圆半径Ri、外圆半径Ro和凸圆半径Rc
{
clrscr();
gotoxy(1,6);
printf("Enter the radius of: he circle. n");
gotoxy(1,8);
printf("Entere in circle radius(>=12.5):n");
scanf("%f",&Ri);
printf("Enter out_circle radius(>=25.0): n");
scanf(%f",&Ro);
printf("Enter convex_radius(>=10.0): n");
scanf("%f",&Rc);
}
void Initialize() // 初始化图形系统
{
int graphdriver,grapgmode,errormode;
graphdriver=DETECT;
initgraph(&graphdriver,&graphmode,"bc>bgi");
errorcode=graphresult();
if(errorcode!=grOk)
{
printf("graphics system error: %s",grapherrormsg(errorcode));
exit(1);
}
mmaxx=getmaxx()/2; // 获取x方向最大分辨率
mmaxy=getmaxy()/2; // 获取y方向最大分辨率
}
void Base_Center_Line() // 画基准线函数
{
flost dash_R;
desh_R=(4*Ro+Ri)/5; // 三个小圆圆心所在的点划圆半径
u1=((4*Ro+Ri)/5)*cos(-30*0.017453); // 确定三个小圆圆心坐标
v1=((4*Ro+Ri)/5)*sin(-30*0.017453);
u2=0.0; // ((4*Ro+Ri)/5)*cos(90*0.017453)
v2=((4*Ro+Ri)/5); // ((4*Ro+Ri)/5)*sin(90*0.017453)
u3=((4*Ro+Ri)/5)*cos(210*0.017453);
v3=((4*Ro+Ri)/5)*sin(210*0.017453);
line(mmaxx-Ro-Rc,mmaxy,mmaxx-(Ro+Rc)/2,mmaxy; // 画基准线
line(mmaxx-(Ro+Rc)/2+5,mmaxy,mmaxx-(Ro+Rc)/2+5,mmaxy);
line(mmaxx-(Ro+Rc)/2+10,mmaxy,mmaxx-(Ro+Rc)/2,mmaxy);
line(mmaxx+(Ro+Rc)/2+5,mmaxy,mmaxx-(Ro+Rc)/2+5,mmaxy);
line(mmaxx+(Ro+Rc)/2+10,mmaxy,mmaxx+Ro+Rc,mmaxy);
line(mmaxx,mmaxy+Ro+Rc,mmaxx,mmaxy+(Ro+Rc)/2+10);
line(mmaxx,mmaxy+(Ro+Rc)/2+5,mmaxx,mmaxy+(Ro+Rc)/2+5);
line(mmaxx,mmaxy+(Ro+Rc)/2,mmaxx,mmaxy-(Ro+Rc)/2+10);
line(mmaxx,mmaxy-(Ro+Rc)/2+5,mmaxx,mmaxy-(Ro+Rc)/2+5);
line(mmaxx,mmaxy-(Ro+Rc)/2,mmaxx,mmaxy-Ro-Rc);
arc(mmaxx,mmaxy,0,25,desh_R); // 画点划圆
arc(mmaxx,mmaxy,28,29,desh_R); // 画点划圆
arc(mmaxx,mmaxy,32,110,desh_R); // 画点划圆
arc(mmaxx,mmaxy,113,114,desh_R); // 画点划圆
arc(mmaxx,mmaxy,117,185,desh_R); // 画点划圆
arc(mmaxx,mmaxy,187,188,desh_R); // 画点划圆
arc(mmaxx,mmaxy,191,255,desh_R); // 画点划圆
arc(mmaxx,mmaxy,258,259,desh_R); // 画点划圆
arc(mmaxx,mmaxy,262,300,desh_R); // 画点划圆
arc(mmaxx,mmaxy,303,304,desh_R); // 画点划圆
arc(mmaxx,mmaxy,307,360,desh_R); // 画点划圆
}
void Known_Circle() // 画已知圆
{
circle(mmaxx,mmaxy,Ri);
circle(mmaxx+u1,mmaxy-v1,Rc/2);
circle(mmaxx+u2,mmaxy-v2,Rc/2);
circle(mmaxx+u3,mmaxy-v3,Rc/2);
}
vooid Link_Arc_Center() // 计算连接圆弧圆心坐标值
{
float A,B,D1,D2,D3,B2_4AC1,B2_4AC2,B2_4AC3;
float BD1,BD2,BD3,Root1,Root2,Root3,temp;
A=Ro*Ro+8*Ro*Rc/5+16*Rc*Rc/25;
B=Ro*Ro+8*Ro*Rc/5-13*Rc*Rc/5;
D1=u1*u1+v1*v1; // D1为计算连接圆弧1与2圆心坐标需要的值,须先算出
D2=u2*u2+v2*v2; // D2为计算连接圆弧3与4圆心坐标需要的值,须先算出
D3=u3*u3+v3*v3; // D3为计算连接圆弧5与6圆心坐标需要的值,须先算出
// 下面几行计算都是为计算连接圆弧圆心坐标值做准备
BD1=B+D1
BD2=B+D2;
BD3=B+D3;
B2_4AC1=u1*u1*(4*A*D1)-BD1*BD1);
B2_4AC2=u2*u2*(4*A*D2)-BD2*BD2);
B2_4AC3=u3*u3*(4*A*D3)-BD3*BD3);
Root1=sqrt(B2_4AC1);
Root2=sqrt(B2_4AC2);
Root3=sqrt(B2_4AC3);
y1=(v1*BD1-Root1)/(2*D1); // 根据圆心坐标所处象限位置,选取正负号
// 连接圆弧1圆心y坐标值
temp=A-y1*y1;
x1=sqrt(temp); // 连接圆弧1圆心x坐标值
y2=(v1*BD1+Root1)/(2*D1); // 连接圆弧2圆心y坐标值
temp=A-y2*y2;
x2=sqrt(temp); // 连接圆弧2圆心x坐标值
y3=(v2*BD2+Root2)/(2*D2); // ±Root2=0
// 连接圆弧3圆心y坐标值
temp=A-y3*y3;
x3=sqrt(temp); // 连接圆弧3圆心x坐标值
y4=(v2*BD2+Root2)/(2*D2); // ±Root2=0
// 连接圆弧4圆心y坐标值
x4=-sqrt(A-y4*y4); // 连接圆弧4圆心x坐标值
y5=(v3*BD3+Root3)/(2*D3); // 连接圆弧5圆心y坐标值
x5=-sqrt(A-y5*y5); // 连接圆弧5圆心x坐标值
y6=(v3*BD3-Root3)/(2*D3); // 连接圆弧6圆心y坐标值
x6=-sqrt(A-y6*y6); // 连接圆弧6圆心x坐标值
}
void Tangent_Point() // 计算切点坐标函数 {
float Rj,Lc,Lo;
Rj=4*Rc/5;
Lc=4.0/5.0; // =Rj/Rc
Lo=Rj/Rc;
cx1=(x1+Lc*u1)/(1+Lc); // 连接圆弧L1与右边凸圆的切点坐标
cy1=(y1+Lc*v1)/(1+Lc);
cx2=(x2+Lc*u1)/(1+Lc); // 连接圆弧L2与右边凸圆的切点坐标
cy2=(y2+Lc*v1)/(1+Lc);
cx3=(x3+Lc*u2)/(1+Lc); // 连接圆弧L3与上边凸圆的切点坐标
cy3=(y3+Lc*v2)/(1+Lc);
cx4=(x4+Lc*u2)/(1+Lc); // 连接圆弧L4与上边凸圆的切点坐标
cy4=(y4+Lc*v2)/(1+Lc);
cx5=(x5+Lc*u3)/(1+Lc); // 连接圆弧L5与左边凸圆的切点坐标
cy5=(y5+Lc*v3)/(1+Lc);
cx6=(x6+Lc*u3)/(1+Lc); // 连接圆弧L6与左边凸圆的切点坐标
cy6=(y6+Lc*v3)/(1+Lc);
ox1=(x1+Lo*0.0)/(1+Lo); // 连接圆弧L1与外圆的切点坐标
oy1=(y1+Lo*0.0)/(1+Lo);
ox2=(x2+Lo*0.0)/(1+Lo); // 连接圆弧L2与外圆的切点坐标
oy2=(y2+Lo*0.0)/(1+Lo);
ox3=(x3+Lo*0.0)/(1+Lo); // 连接圆弧L3与外圆的切点坐标
oy3=(y3+Lo*0.0)/(1+Lo);
ox4=(x4+Lo*0.0)/(1+Lo); // 连接圆弧L4与外圆的切点坐标
oy4=(y4+Lo*0.0)/(1+Lo);
ox5=(x5+Lo*0.0)/(1+Lo); // 连接圆弧L5与外圆的切点坐标
oy5=(y5+Lo*0.0)/(1+Lo);
ox6=(x6+Lo*0.0)/(1+Lo); // 连接圆弧L6与外圆的切点坐标
oy6=(y6+Lo*0.0)/(1+Lo);
}
void Myarc(float ctx,float cty,float startx,float starty,float endx,float endy,float R)
{
float sx,sy,ex,ey,sangle,eangle;
sx=startx-ctx;
sy=starty-cty;
ex=endx-ctx;
ey=endy-cty;
if(sx!=0.0)
{
// θ=arctg y/x, (x>0.0)
// θ=arctg y/x+π,(x<0.0)
if(sx>0.00)sangle=atan(sy/sx); // 将起点转化成起始角
if(sx<0.0)sangle=atan(sy/sx)+3.1415926; // 将起点转化成起始角
}
else
{
if(sy>0.0)sangle=3.1415926/2; // 将起点转化成起始角
if(sy<0.0)sangle=3*3.1415926/2; // 将起点转化成起始角
}
if(ex!=0.0)
{
if(ex>0.0)eangle=atan(ey/ex); // 将终点转化成终止角
if(ex<0.0)eangle=atan(ey/ex)+3.1415926; // 将终点转化成终止角
}
else
{
if(ey>0.0)eangle=3.1415926/2; // 将终点转化成终止角
if(ey<0.0)eangle=3*3.1415926/2; // 将终点转化成终止角
}
sangle=sangle/0.017453; // 1=1o/0.017453
eangle=eangle/0.017453;
arc(mmaxx+ctx,mmaxy-cty,sangle,eangle,R); // 画出圆弧
}
void Out_Link_Arc()
{
float Rj;
Rj=4*Rc/5;
Myarc(u1,v1,cx1,cy1,cx2,cy2,Rc);
// 用凸圆弧1圆心、圆弧两端坐标和半径画出凸圆弧1,其它圆弧的绘制类同。
Myarc(x2,y2,ox2,oy2,cx2,cy2,Rj);
Myarc(0.0,0.0,ox2,oy2,ox3,oy3,Ro);
Myarc(x3,y3,cx3,cy3,ox3,oy3,Rj);
Myarc(u2,v2,cx3,cy3,cx4,cy4,Rc);
Myarc(x4,y4,ox4,oy4,cx4,cy4,Rj);
Myarc(0.0,0.0,ox4,oy4,ox5,oy5,Ro);
Myarc(x5,y5,cx5,cy5,ox5,oy5,Rj);
Myarc(u3,v3,cx5,cy5,cx6,cy6,Rc);
Myarc(x6,y6,ox6,oy6,cx6,cy6,Rj);
Myarc(0.0,0.0,ox6,oy6,ox1,oy1,Ro);
Myarc(x1,y1,cx1,cy1,ox1,oy1,Rj);
}
void main()
{
Enter_Data(); // 输入数据值
Initialize(); // 图形初始化
Base_Center_Line(); // 画基准线
Known_Circle(); // 画已知圆
Link_Arc_Center(); // 求连接圆弧圆心
Tangent_Point(); // 求切点
Out_Link_Arc(); // 画出外圆弧、凸圆弧和连接圆弧
getche(); // 使图形暂留在屏幕上
closegraph(); // 释放图形系统占用的内存,返回文本模式
}