Arc不够快吗????你可以先Arc到一个MemoryDC里面吗 不过你总得给定些什么条件吧,和Arc一样得参数?BOOL Arc( HDC hdc, // handle to device context int nLeftRect, // x-coord of rectangle's upper-left corner int nTopRect, // y-coord of rectangle's upper-left corner int nRightRect, // x-coord of rectangle's lower-right corner int nBottomRect, // y-coord of rectangle's lower-right corner int nXStartArc, // x-coord of first radial ending point int nYStartArc, // y-coord of first radial ending point int nXEndArc, // x-coord of second radial ending point int nYEndArc // y-coord of second radial ending point );
先检查一下你的信用....
kidding...
不过你总得给定些什么条件吧,和Arc一样得参数?BOOL Arc(
HDC hdc, // handle to device context
int nLeftRect, // x-coord of rectangle's upper-left corner
int nTopRect, // y-coord of rectangle's upper-left corner
int nRightRect, // x-coord of rectangle's lower-right corner
int nBottomRect, // y-coord of rectangle's lower-right corner
int nXStartArc, // x-coord of first radial ending point
int nYStartArc, // y-coord of first radial ending point
int nXEndArc, // x-coord of second radial ending point
int nYEndArc // y-coord of second radial ending point
);
BOOM...好大的牛皮爆了
const long width=800,height=600;//屏幕窗口的高度和宽度,最好设置的大一些//求出圆和矩形(0,0,widht,height)的交点。两个凸曲线的交点最多只有2个
int intersect(CPoint center,long r,CPoint pt[2]);void stand(long&x,long&y,long r)
{
double t = r/sqrt((double)x*x+(double)y*y);
x = x*t; y = y*t;
}void Arc(CPoint center,long r)
{
if(r<10000)
//调用API函数并返回
CPoint pt[2];
if(intersect(center,r,pt)!=2)
return;//看不见
//如果2点直线能满足视觉要求画直线OK //中间插1个点
CPoint mid = (pt[0]+pt[1])/2-center;
stand(mid.x,min.y,r);
//画三点折线应该够了
…………
return; //不怕速度慢可以多插几个点
…………
return;
}
你只要看过图形学的书就应该会了,不要过分看重这个
DrawArc函数就是你要的需求#include <windows.h>
#include <math.h>
#include "resource.h"
/*
Ellipse:
1)-1<dy/dx<0 -> 0<b^2*x/(a^2*y)<1 -> b^2*x<a^2*y
可以看出y的减少率没有x增长率高,我们应该增加x来看y的增长,于是排除(x,y-1)的可能。
如果F(x,y)<=0,对于下一个点我们应该尽量向外推,因此
x(i+1)=x(i)+1,y(i+1)=y(i),dF=2*b^2*x+b^2
如果F(x,y)>0,对于下一个点我们应该尽量向内推,因此
x(i+1)=x(i)+1,y(i+1)=y(i)-1,dF=2*b^2*x+b^2-2*a^2*y+a^2
2)dy/dx>=-1 -> b^2*x>=a^2*y
可以看出y的减少率比x增长率高,我们应该减少y来看x的增长,于是排除(x+1,y)的可能。
如果F(x,y)<=0,对于下一个点我们应该尽量向外推,因此
x(i+1)=x(i)+1,y(i+1)=y(i)-1,dF=2*b^2*x+b^2-2*a^2*y+a^2
如果F(x,y)>0,对于下一个点我们应该尽量向内推,因此
x(i+1)=x(i),y(i+1)=y(i)-1,dF=-2*a^2*y+a^2
*/#define G(x,y) b*b*x*x+a*a*y*y-a*a*b*bvoid DrawPixelPart(HDC hdc,int x0,int y0,int x,int y,int part,COLORREF color)
{
switch(part)
{
case 0:
SetPixel(hdc,x0-x,y0-y,color);break;
case 1:
SetPixel(hdc,x0+x,y0-y,color);break;
case 2:
SetPixel(hdc,x0+x,y0+y,color);break;
case 3:
SetPixel(hdc,x0-x,y0+y,color);break;
default:
break;
}
}
#define PI 3.14159
void DrawArcPart(HDC hdc,int x0,int y0,int a,int b,int arc_start,int arc_end,int part,COLORREF color)
{
int F,x,y,B=b*b,A=a*a,Bx,Ay,xend,yend;
x=((double)a)*sin(arc_start*PI/180)+0.5;y=((double)b)*cos(arc_start*PI/180)+0.5;
xend=((double)a)*sin(arc_end*PI/180)+0.5;yend=((double)b)*cos(arc_end*PI/180)+0.5;
xend=max(xend,x);yend=min(yend,y);
Bx=B*x;Ay=A*y;
F=G(x,y);
while(Bx<Ay&&x<=xend&&y>=yend)
{
DrawPixelPart(hdc,x0,y0,x,y,part,color);
if(F>0)
{
x++;y--;F+=2*Bx+B-2*Ay+A;Bx+=B;Ay-=A;
}
else
{
x++;F+=2*Bx+B;Bx=B*x;Bx+=B;
}
}
if(Bx>=Ay)
{
while(x<=xend&&y>=yend)
{
DrawPixelPart(hdc,x0,y0,x,y,part,color);
if(F>0)
{
y--;F+=A-2*Ay;Ay-=A;
}
else
{
x++;y--;F+=2*Bx+B-2*Ay+A;Bx+=B;Ay-=A;
}
}
}
}#define DrawPart(arc_start,arc_end,part) DrawArcPart(hdc,x0,y0,a,b,arc_start,arc_end,part,color)//用Bresenham算法生成的椭圆弧线,(x0,y0)为圆心,a为x截距,b为y截距,arc_start和arc_end使用角度表示,从-x旋转分别是角度开始/结束,color是颜色
void DrawArc(HDC hdc,int x0,int y0,int a,int b,int arc_start,int arc_end,COLORREF color)
{
int i,part_start,part_end;
if(arc_start>arc_end)//保证arc_end>arc_start
{
i=arc_start;
arc_start=arc_end;
arc_end=i;
}
if(arc_end-arc_start>=360)//两个角差别大于360,就是全画
{
DrawPart(0,90,0);
DrawPart(0,90,1);
DrawPart(0,90,2);
DrawPart(0,90,3);
return;
}
arc_start%=360;arc_end%=360;
part_start=arc_start/90;part_end=arc_end/90;
if(arc_start>arc_end)//后接式
{
if(part_start%2)//偶数象限
DrawPart(arc_start%90,90,part_start);
else
DrawPart(90-arc_start%90,90,part_start);
for(i=part_start+1;i<4;i++)
DrawPart(0,90,i); if(part_end%2)//偶数象限
DrawPart(0,arc_end%90,part_end);
else
DrawPart(90-arc_end%90,90,part_end);for(i=0;i<part_end;i++)
DrawPart(0,90,i);
}
else//前置
{
if(part_end!=part_start)//不在一个象限
{
if(part_start%2)//偶数象限
DrawPart(arc_start%90,90,part_start);
else
DrawPart(0,90-arc_start%90,part_start);
if(part_end%2)//偶数象限
DrawPart(0,arc_end%90,part_end);
else
DrawPart(90-arc_end%90,90,part_end); for(i=part_start+1;i<part_end;i++)
DrawPart(0,90,i);
}
else
DrawPart(arc_start%90,arc_end%90,part_start);
}
}
INT_PTR CALLBACK DialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
HANDLE hdc;
PAINTSTRUCT ps;switch(uMsg)
{
case WM_PAINT:
hdc=BeginPaint(hwndDlg,&ps);
DrawArc(hdc,100,50,70,40,0,150,RGB(255,0,0));EndPaint(hwndDlg,&ps);
return TRUE;
case WM_COMMAND:
switch( LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwndDlg,0);
return TRUE;
}
break;
default:
break;
}
return FALSE;
}int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
DialogBox(hInstance,MAKEINTRESOURCE (IDD_DIALOG1),NULL,DialogProc);}
void circleMidpoint(int xCenter,int yCenter,int radius,HDC dc)
{
int x = 0;
int y = radius;
int p=1-radius;
while(x<y)
{
x++;
if(p<0)
{
p+=2*x+1;
}
else
{
y--;
p+=2*(x-y)+1;
}
SetPixel(dc,xCenter+x,yCenter+y,RGB(255,0,0));
SetPixel(dc,xCenter-x,yCenter+y,RGB(255,0,0));
SetPixel(dc,xCenter+x,yCenter-y,RGB(255,0,0));
SetPixel(dc,xCenter-x,yCenter-y,RGB(255,0,0)); SetPixel(dc,xCenter+y,yCenter+x,RGB(255,0,0));
SetPixel(dc,xCenter-y,yCenter+x,RGB(255,0,0));
SetPixel(dc,xCenter+y,yCenter-x,RGB(255,0,0));
SetPixel(dc,xCenter-y,yCenter-x,RGB(255,0,0));
}
}
用以下参数调用DrawArc,后所画的圆有问题,
DrawArc(hdc,1000,1000,1800,1800,0,360,RGB(255,0,0));
当然,在nt机器上,直接使用arc是可以支持到long的大小的半径,而且使用dc的clip,也支持的很好,根本不需要使用所谓的图形学算法。
p1,p2为计算的点,r为半径。p为中心。
::Arc(hDC,p.x-r,p.y-r,p.x+r,p.y+r,p2.x,p2.y,p1.x,p1.y);
当r 》 32768在nt下,这个函数是成功的,但9x可能不行。只是说可能,不是觉得,可能的意思是说虽然做错了,但你看不出来;不能是说它可能在屏幕上画了条任意的线。
当然API是不行的
自己 构造出 折线进行模拟就可以了。
我有 程序,但不能给你
因为是 公司的,保密
编写CAD软件应该采用现成的内核,比如AutoCAD的内核是ACIS,UG和SolidWorks的内核
是parasolid,还有北航海尔的CAXA的内核也是parasolid。
所谓内核实际上就是一个类库,里面定义了图形数据的存储格式以及大量的图形算法。
采用CAD内核,也许只需要一两行代码就能解决你所提到的问题。
但是ACIS和parasolid都是需要购买的,D版市场上也未曾出现过。
Marta DATAVISION公司的CAD内核OpenCASCADE是开放源代码的,
你可以去http://www.opencascade.com看看。
采用OpenCASCADE,不要说二维绘图软件,做三维CAD软件也是有可能的。
但进行过 与 Microstation的测试。
精度上 绝对不差于 Microstation。感觉比较麻烦,但并没有什么特别高深的东西
会计算机图形学 就可以高定
赶紧去吧,看几页书也比在这闲聊强.别吊死在一棵树上了.没见过一个公司为了一个函数等几年的.
to wxyhzzp(小王):
其实你的问题是截图问题,如果要画如此大的园必须作截图优化,就是算出图在目标矩阵中的弧线(可能分割多弧)的开始和结束位置。然后再画图。其实半径4000以上的弧在各个象限的截图仅仅是1度的大小,但是如果不优化,则需要造成大量运算。
将Arc确定的椭圆转化为Bezier(这方面已有文章介绍),然后根据Bezier细分的方法将其细分到比窗口矩形略大即可(可把不需要的部分舍去只细分与窗口相交的部分),这时可用PolyBezier来画。但实在没想出来Arc函数为何会如此之慢
因椭圆可分为4段Bezier,故可先省去3/4,剩下的部分水平和垂直长度仅为100000,细分10次后即可使长度在窗口范围内了,原理如下:
100000第一次细分后长度为50000,舍去无用的一半,进行第二次细分,如此下去细分10次后长度仅为1000000/(2^10)大约为100,这时画起来应该很快。上述方法未经测试,但根据本人做过的更复杂的程序来看,这个速度应该通达到你的要求,除非你不但不优化代码反而将其“劣化”,这就不关我的事了,呵呵。
高效的画象素函数,可以用汇编直接写。以前是没有DirectDraw的。
大家都想到了,可以把不可见部分跳掉。而且还可以想办法直接写显存。
对此,前边朋友说的用线段近似就是一例解决,实际上CAD画的小圆弧确实是有棱角的,说起来其实也不是它高明的地方。
我接着说:
这里圆弧用直线段近似有特殊的地方,这些线段并不需要是"任意"斜率的,所以有好多东西可以做得效率高一点.
比方一个圆用N段直线近似,那这些线段的斜率:
K=tg(2*pi/n),n=0 to n/2-1;
对于每一条线段,可以从起点开始,按一定的序列给X,Y增量,就不需要逐点比较判断运算了.(图形学里的直线画法就是需要逐点判断,然后决定X,Y增量)
如果你真的知道,何必在这里卖弄了,我觉得你更加应该写一片论文出来,这样更能体现你的学识? 诚然一个产品性质的软件要比一个测试性质的软件代码量要大很多,我觉得在论坛中没有必要讨论产品性质的软件,那些东西过于细化了,但是论原理大家都懂。
你要是真的能够做出来,应该把你的程序贴出来。然后对重要部分加以说明。
当然,纯显示时间约为0
btw:我没用过AutoCAD
tonyzym(tony):
请说说你的画圆程序里头有什么独到的地方可以使你比别人快。现在是发散思维讨论方法的时候。最后10条想法里头有2,3条被使用就不错了。