圆大小固定,里面正方形个数随机,求个排列的办法,使图形尽量美观
30 个解决方案
#1
你这是彩票类程序?帮你顶一下。
#2
为什么这么说呢?
#3
各位高手,来教教我啊
#4
刚不给你回了么,你要的不是这个效果么?
可以这样设计算法,不过效率可能比较低,假设圆的直径是d,小正方形的个数是n,按你说的这个n是指定的,可以是任何一个数量,小正方形的边长是L,,但如果是正方形的话不能保证边缘的正方形一定和圆相交,下面是伪代码
不知道楼主是不是这个意思,还是我理解错了。
可以这样设计算法,不过效率可能比较低,假设圆的直径是d,小正方形的个数是n,按你说的这个n是指定的,可以是任何一个数量,小正方形的边长是L,,但如果是正方形的话不能保证边缘的正方形一定和圆相交,下面是伪代码
L初始为0
while(TRUE)//循环
{
L+=1 每次循环边长+1
//用L长的小正方形去填充满边长为d大正方形,那个圆就是这个大正方形的内切圆,假设用了x个小正方形
x=d^2/L^2 //x取整
t=x
for(i=0;i<t;i++) //循环x次
{
检测第i个小正方形的4个顶点是不是在直径为d的内切圆内,是-继续,不是-则x-1
}
比较x和n,当x第一次小于n的时候,中断循环
}
L值即为在n个小正方形填充圆情况下的小正方形边长
不知道楼主是不是这个意思,还是我理解错了。
#5
是这个意思,可圆和小正方形都是画线画上去的,怎么判断顶点是不是在园内啊
#6
你画小正方形也得要4个顶点坐标才能画啊,判断一个点是不是在一个圆内,这个。。。。。,这个咱们初中就学过-_-!,这点到圆心的距离小于半径就在园内,大于就在圆外,等于就在圆上,还是给你写个例子
假如一个顶点在v(x,y),圆心在c(x',y')
s=sqrt((x-x')^2+(y-y')^2); //勾股定理,s是到圆心的距离
s<D/2就在园内 //D是直径,所以除以2
假如一个顶点在v(x,y),圆心在c(x',y')
s=sqrt((x-x')^2+(y-y')^2); //勾股定理,s是到圆心的距离
s<D/2就在园内 //D是直径,所以除以2
#7
正方形大小是否统一?位置是否可以重叠?
#8
大小一样,位置不能重叠,必须一个挨一个
#9
那就不算随机了
假设小正方形边长为x
则有x*x种(或更少)排法
全部试一遍就行了
假设小正方形边长为x
则有x*x种(或更少)排法
全部试一遍就行了
#10
数量是随机的,大小也会随数量缩小,不过全部的正方形都是一样大。
你能将排法说的详细一些吗?
#11
假设小正方形边长为a,就是以园的最左点x坐标m和最上点y坐标n为起始点(m,n),
画出横线(x=m)和竖线(y=n),再移a像素划出横线(x=m+a)和竖线(y=n+a),。。。。它们构成一种正方形的组合
然后以(m+1,n+1)为起始点画出横线(x=m+1)和竖线(y=n+1),再移a像素划出横线(x=m+1+a)和竖线(y=n+1+a),。。。。它们构成第2种正方形的组合
。。。
画出横线(x=m)和竖线(y=n),再移a像素划出横线(x=m+a)和竖线(y=n+a),。。。。它们构成一种正方形的组合
然后以(m+1,n+1)为起始点画出横线(x=m+1)和竖线(y=n+1),再移a像素划出横线(x=m+1+a)和竖线(y=n+1+a),。。。。它们构成第2种正方形的组合
。。。
#12
我请教个问题,delphi能不能先画个网状的图形,然后画个圆,最后只现在圆里圈上的小方格呢
#13
可以啊,循环画横线和竖线,间隔都是a
然后画园
圆心的坐标也是a*a种选择
然后画园
圆心的坐标也是a*a种选择
#14
先说说画这个干嘛。。
#15
能给个简单例子吗?我不太熟悉delphi
#16
涉及保密问题,我不能说啊大哥,这是我的任务,明天交活了,可我现在还没做完,所以到这里请各位高手指教啊。
#17
因为是整形的 算法肯定 不是严格相切的,
这个条件不是严格的 求解是仅仅是美观 。。
画出来就行了。。
这个条件不是严格的 求解是仅仅是美观 。。
画出来就行了。。
#18
我现在都没明白咋做呢 我没用过delphi画图 请大哥详细点说啊,最好能给点简单的代码,我也好参考
#19
你用delphi做过什么?
还是用熟悉的 语言写吧。。
还是用熟悉的 语言写吧。。
#20
要是让用别的语言我早用了。。。只能用delphi做
#21
我第一次用delphi
#22
用穷举法吧。
#23
高手 ,不要说名词,我不明白,给个简单的例子呗
#24
-_-!,你这样难度太大了,从来没用过delphi怎么写啊,吃晚饭我给你写个吧,就用我那个算法,很简单的
#25
下面是代码,由于屏幕坐标都是整数坐标,所以无法精确的画出指定个数的小正方形,而且图形并不对称,如果要对称的话,可以只计算1/4的顶点数,就是垂直和水平两条直径把园分成4分,只求其中一份的所有定点,然后推算出其3个部分的顶点坐标,这样图形就对称了,而且效率更高,不过可能实际的小正方形数量会更不准确,你自己试验一下。
结果如下图:
源代码:
结果如下图:
源代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
PaintBox1: TPaintBox;
Edit1: TEdit;
Label1: TLabel;
Label2: TLabel;
procedure PaintBox1Paint(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Vertexes:array of TPoint; //存储顶点
CurL:integer; //当前的小正方形边长
DrawState:boolean=false; //是否可以在OnPaint事件里面绘图
implementation
{$R *.dfm}
procedure AddVertex(vt:TPoint);
begin
SetLength(Vertexes,Length(Vertexes)+1);
Vertexes[Length(Vertexes)-1]:=vt;
end;
function RectInPie(vTopLeft,COC:TPoint;CurL,R:integer):boolean;
begin
Result:=(sqrt(sqr((vTopLeft.X - COC.X))+sqr((vTopLeft.Y - COC.Y)))<=R) and
(sqrt(sqr((vTopLeft.X+CurL - COC.X))+sqr((vTopLeft.Y - COC.Y)))<=R) and
(sqrt(sqr((vTopLeft.X+CurL - COC.X))+sqr((vTopLeft.Y+CurL - COC.Y)))<=R) and
(sqrt(sqr((vTopLeft.X - COC.X))+sqr((vTopLeft.Y+CurL - COC.Y)))<=R);
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
var
rClient:TRect;
i:integer;
pt:TPoint;
begin
rClient:=PaintBox1.ClientRect ;
with PaintBox1.Canvas do begin
Brush.Color:=clBlack;
Brush.Style:=bsSolid;
Rectangle(0,0,rClient.Right,rClient.Bottom);
//以上代码把PaintBox1的背景涂成黑色
//画圆
Pen.Color:=clYellow;
Ellipse(0,0,rClient.Right,rClient.Bottom);
if DrawState then begin //绘制小正方形
Pen.Color:=clBlue; //边框蓝色
Brush.Color:=clLime; //填充亮绿色
for i:=0 to Length(Vertexes) -1 do begin
pt:=Vertexes[i];
Rectangle(pt.X,pt.Y,pt.X+CurL,pt.Y+CurL);
end;
end;
end;//end with
end;
procedure TForm1.Button1Click(Sender: TObject);
var
L,n,r,x:integer;
nCount,nCountPerLine,nLine,i:integer;
V:TPoint; //左上角顶点
begin
if not TryStrToInt(Edit1.Text,n) then exit; //指定用多少个小正方形
DrawState:=false; //暂时不允许绘图
r:=PaintBox1.ClientRect.Right div 2; //圆半径
L:=3; //小正方形边长
while true do begin
Inc(L); //从4开始,太小没意思
SetLength(Vertexes,0); //清空顶点
x:=sqr(2*r) div sqr(L); //求要用多少个小正方形填充大正方形
nCount:=x;
nCountPerLine:=Round(2*r/L); //一行有多少个小正方形
nLine:=0; //从第一行开始
for i:=1 to x do begin
if i mod nCountPerLine=0 then Inc(nLine);//换行
//求小正方形的左上角坐标
V.X:=L*(i mod nCountPerLine);
V.Y:=nLine*L;
if RectInPie(V,Point(r,r),L,r) then
AddVertex(V)
else
Dec(nCount);
end; //end for
if nCount<n then begin
CurL:=L; //求得小正方形边长,并终止循环
Label2.Caption:=Format('实际用了 %d 个正方形(边长%d)',[nCount,CurL]);
break;
end;
end; //end while
DrawState:=true;
PaintBox1.Invalidate;
end;
end.
#26
多谢大哥
#27
大哥,数量少了是什么原因,我应该改什么地方能让数量接近些
#28
你是用数量去推导边长,而且要填满一个圆形,这样不太正确,因为实际上边长是可以确定的,而数量不能确定,原因就是由于屏幕坐标都是整数,无法精确的绘制图形,边长的变化和数量的变化是离散的,可能边长增加或减少一点,数量不变,也可能边长每次增加10而每次减少的数量都不一样,即假如指定100个等大的正方形填满一个圆,在GDI模式实际上可能根本做不到,除非不填满。下面是优化过的代码,你可以再试一下,这样图形是上下左右对称的,好看而且效率高,不过数量更不准确
procedure TForm1.Button1Click(Sender: TObject);
var
L,n,r:integer;
nCount,nCountPerLine,nLine,i,t:integer;
V:TPoint;
begin
if not TryStrToInt(Edit1.Text,n) then exit; //指定用多少个小正方形
ASSERT(n mod 4=0,'数目应该为4的倍数');
DrawState:=false; //暂时不允许绘图
r:=PaintBox1.ClientRect.Right div 2; //圆半径
L:=3; //小正方形边长
while true do begin //求左上1/4圆周那个扇形可以容纳多少个边长为L的小正方形
Inc(L);
SetLength(Vertexes,0); //清空顶点
nLine:=r div L;//一共nLine行
for i:=1 to nLine do begin
//计算第i行可以容纳多少个边长为L的小正方形
nCountPerLine:=Trunc(sqrt(sqr(r)-sqr(i*L))/L); //截断,不要四舍五入
for t:=1 to nCountPerLine do begin
V.X:=r-t*L;
V.Y:=r-i*L;
AddVertex(V);
end;//end 2 for
end; //end 1 for
nCount:=Length(Vertexes);
ASSERT(nCount>0);
if nCount<=n div 4 then begin
CurL:=L;
break;
end
end;//end 1 while
for i:=0 to Length(Vertexes)-1 do //右上侧
AddVertex(Point(2*r-Vertexes[i].X-CurL,Vertexes[i].Y)); //横坐标和垂直半径对称
for i:=0 to Length(Vertexes)-1 do //上半圆整个沿水平直径再翻一次
AddVertex(Point(Vertexes[i].X,2*r-Vertexes[i].Y-CurL));
Label2.Caption:=Format('实际用了 %d 个小正方形(边长%d)',[Length(Vertexes),CurL]);
DrawState:=true;
PaintBox1.Invalidate;
end;
#29
有两种对称形状,一种是圆点是一个格子中间的,另一种是圆点是四个格子交界的。
#30
多谢了
#1
你这是彩票类程序?帮你顶一下。
#2
为什么这么说呢?
#3
各位高手,来教教我啊
#4
刚不给你回了么,你要的不是这个效果么?
可以这样设计算法,不过效率可能比较低,假设圆的直径是d,小正方形的个数是n,按你说的这个n是指定的,可以是任何一个数量,小正方形的边长是L,,但如果是正方形的话不能保证边缘的正方形一定和圆相交,下面是伪代码
不知道楼主是不是这个意思,还是我理解错了。
可以这样设计算法,不过效率可能比较低,假设圆的直径是d,小正方形的个数是n,按你说的这个n是指定的,可以是任何一个数量,小正方形的边长是L,,但如果是正方形的话不能保证边缘的正方形一定和圆相交,下面是伪代码
L初始为0
while(TRUE)//循环
{
L+=1 每次循环边长+1
//用L长的小正方形去填充满边长为d大正方形,那个圆就是这个大正方形的内切圆,假设用了x个小正方形
x=d^2/L^2 //x取整
t=x
for(i=0;i<t;i++) //循环x次
{
检测第i个小正方形的4个顶点是不是在直径为d的内切圆内,是-继续,不是-则x-1
}
比较x和n,当x第一次小于n的时候,中断循环
}
L值即为在n个小正方形填充圆情况下的小正方形边长
不知道楼主是不是这个意思,还是我理解错了。
#5
是这个意思,可圆和小正方形都是画线画上去的,怎么判断顶点是不是在园内啊
#6
你画小正方形也得要4个顶点坐标才能画啊,判断一个点是不是在一个圆内,这个。。。。。,这个咱们初中就学过-_-!,这点到圆心的距离小于半径就在园内,大于就在圆外,等于就在圆上,还是给你写个例子
假如一个顶点在v(x,y),圆心在c(x',y')
s=sqrt((x-x')^2+(y-y')^2); //勾股定理,s是到圆心的距离
s<D/2就在园内 //D是直径,所以除以2
假如一个顶点在v(x,y),圆心在c(x',y')
s=sqrt((x-x')^2+(y-y')^2); //勾股定理,s是到圆心的距离
s<D/2就在园内 //D是直径,所以除以2
#7
正方形大小是否统一?位置是否可以重叠?
#8
大小一样,位置不能重叠,必须一个挨一个
#9
那就不算随机了
假设小正方形边长为x
则有x*x种(或更少)排法
全部试一遍就行了
假设小正方形边长为x
则有x*x种(或更少)排法
全部试一遍就行了
#10
数量是随机的,大小也会随数量缩小,不过全部的正方形都是一样大。
你能将排法说的详细一些吗?
#11
假设小正方形边长为a,就是以园的最左点x坐标m和最上点y坐标n为起始点(m,n),
画出横线(x=m)和竖线(y=n),再移a像素划出横线(x=m+a)和竖线(y=n+a),。。。。它们构成一种正方形的组合
然后以(m+1,n+1)为起始点画出横线(x=m+1)和竖线(y=n+1),再移a像素划出横线(x=m+1+a)和竖线(y=n+1+a),。。。。它们构成第2种正方形的组合
。。。
画出横线(x=m)和竖线(y=n),再移a像素划出横线(x=m+a)和竖线(y=n+a),。。。。它们构成一种正方形的组合
然后以(m+1,n+1)为起始点画出横线(x=m+1)和竖线(y=n+1),再移a像素划出横线(x=m+1+a)和竖线(y=n+1+a),。。。。它们构成第2种正方形的组合
。。。
#12
我请教个问题,delphi能不能先画个网状的图形,然后画个圆,最后只现在圆里圈上的小方格呢
#13
可以啊,循环画横线和竖线,间隔都是a
然后画园
圆心的坐标也是a*a种选择
然后画园
圆心的坐标也是a*a种选择
#14
先说说画这个干嘛。。
#15
能给个简单例子吗?我不太熟悉delphi
#16
涉及保密问题,我不能说啊大哥,这是我的任务,明天交活了,可我现在还没做完,所以到这里请各位高手指教啊。
#17
因为是整形的 算法肯定 不是严格相切的,
这个条件不是严格的 求解是仅仅是美观 。。
画出来就行了。。
这个条件不是严格的 求解是仅仅是美观 。。
画出来就行了。。
#18
我现在都没明白咋做呢 我没用过delphi画图 请大哥详细点说啊,最好能给点简单的代码,我也好参考
#19
你用delphi做过什么?
还是用熟悉的 语言写吧。。
还是用熟悉的 语言写吧。。
#20
要是让用别的语言我早用了。。。只能用delphi做
#21
我第一次用delphi
#22
用穷举法吧。
#23
高手 ,不要说名词,我不明白,给个简单的例子呗
#24
-_-!,你这样难度太大了,从来没用过delphi怎么写啊,吃晚饭我给你写个吧,就用我那个算法,很简单的
#25
下面是代码,由于屏幕坐标都是整数坐标,所以无法精确的画出指定个数的小正方形,而且图形并不对称,如果要对称的话,可以只计算1/4的顶点数,就是垂直和水平两条直径把园分成4分,只求其中一份的所有定点,然后推算出其3个部分的顶点坐标,这样图形就对称了,而且效率更高,不过可能实际的小正方形数量会更不准确,你自己试验一下。
结果如下图:
源代码:
结果如下图:
源代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
PaintBox1: TPaintBox;
Edit1: TEdit;
Label1: TLabel;
Label2: TLabel;
procedure PaintBox1Paint(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Vertexes:array of TPoint; //存储顶点
CurL:integer; //当前的小正方形边长
DrawState:boolean=false; //是否可以在OnPaint事件里面绘图
implementation
{$R *.dfm}
procedure AddVertex(vt:TPoint);
begin
SetLength(Vertexes,Length(Vertexes)+1);
Vertexes[Length(Vertexes)-1]:=vt;
end;
function RectInPie(vTopLeft,COC:TPoint;CurL,R:integer):boolean;
begin
Result:=(sqrt(sqr((vTopLeft.X - COC.X))+sqr((vTopLeft.Y - COC.Y)))<=R) and
(sqrt(sqr((vTopLeft.X+CurL - COC.X))+sqr((vTopLeft.Y - COC.Y)))<=R) and
(sqrt(sqr((vTopLeft.X+CurL - COC.X))+sqr((vTopLeft.Y+CurL - COC.Y)))<=R) and
(sqrt(sqr((vTopLeft.X - COC.X))+sqr((vTopLeft.Y+CurL - COC.Y)))<=R);
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
var
rClient:TRect;
i:integer;
pt:TPoint;
begin
rClient:=PaintBox1.ClientRect ;
with PaintBox1.Canvas do begin
Brush.Color:=clBlack;
Brush.Style:=bsSolid;
Rectangle(0,0,rClient.Right,rClient.Bottom);
//以上代码把PaintBox1的背景涂成黑色
//画圆
Pen.Color:=clYellow;
Ellipse(0,0,rClient.Right,rClient.Bottom);
if DrawState then begin //绘制小正方形
Pen.Color:=clBlue; //边框蓝色
Brush.Color:=clLime; //填充亮绿色
for i:=0 to Length(Vertexes) -1 do begin
pt:=Vertexes[i];
Rectangle(pt.X,pt.Y,pt.X+CurL,pt.Y+CurL);
end;
end;
end;//end with
end;
procedure TForm1.Button1Click(Sender: TObject);
var
L,n,r,x:integer;
nCount,nCountPerLine,nLine,i:integer;
V:TPoint; //左上角顶点
begin
if not TryStrToInt(Edit1.Text,n) then exit; //指定用多少个小正方形
DrawState:=false; //暂时不允许绘图
r:=PaintBox1.ClientRect.Right div 2; //圆半径
L:=3; //小正方形边长
while true do begin
Inc(L); //从4开始,太小没意思
SetLength(Vertexes,0); //清空顶点
x:=sqr(2*r) div sqr(L); //求要用多少个小正方形填充大正方形
nCount:=x;
nCountPerLine:=Round(2*r/L); //一行有多少个小正方形
nLine:=0; //从第一行开始
for i:=1 to x do begin
if i mod nCountPerLine=0 then Inc(nLine);//换行
//求小正方形的左上角坐标
V.X:=L*(i mod nCountPerLine);
V.Y:=nLine*L;
if RectInPie(V,Point(r,r),L,r) then
AddVertex(V)
else
Dec(nCount);
end; //end for
if nCount<n then begin
CurL:=L; //求得小正方形边长,并终止循环
Label2.Caption:=Format('实际用了 %d 个正方形(边长%d)',[nCount,CurL]);
break;
end;
end; //end while
DrawState:=true;
PaintBox1.Invalidate;
end;
end.
#26
多谢大哥
#27
大哥,数量少了是什么原因,我应该改什么地方能让数量接近些
#28
你是用数量去推导边长,而且要填满一个圆形,这样不太正确,因为实际上边长是可以确定的,而数量不能确定,原因就是由于屏幕坐标都是整数,无法精确的绘制图形,边长的变化和数量的变化是离散的,可能边长增加或减少一点,数量不变,也可能边长每次增加10而每次减少的数量都不一样,即假如指定100个等大的正方形填满一个圆,在GDI模式实际上可能根本做不到,除非不填满。下面是优化过的代码,你可以再试一下,这样图形是上下左右对称的,好看而且效率高,不过数量更不准确
procedure TForm1.Button1Click(Sender: TObject);
var
L,n,r:integer;
nCount,nCountPerLine,nLine,i,t:integer;
V:TPoint;
begin
if not TryStrToInt(Edit1.Text,n) then exit; //指定用多少个小正方形
ASSERT(n mod 4=0,'数目应该为4的倍数');
DrawState:=false; //暂时不允许绘图
r:=PaintBox1.ClientRect.Right div 2; //圆半径
L:=3; //小正方形边长
while true do begin //求左上1/4圆周那个扇形可以容纳多少个边长为L的小正方形
Inc(L);
SetLength(Vertexes,0); //清空顶点
nLine:=r div L;//一共nLine行
for i:=1 to nLine do begin
//计算第i行可以容纳多少个边长为L的小正方形
nCountPerLine:=Trunc(sqrt(sqr(r)-sqr(i*L))/L); //截断,不要四舍五入
for t:=1 to nCountPerLine do begin
V.X:=r-t*L;
V.Y:=r-i*L;
AddVertex(V);
end;//end 2 for
end; //end 1 for
nCount:=Length(Vertexes);
ASSERT(nCount>0);
if nCount<=n div 4 then begin
CurL:=L;
break;
end
end;//end 1 while
for i:=0 to Length(Vertexes)-1 do //右上侧
AddVertex(Point(2*r-Vertexes[i].X-CurL,Vertexes[i].Y)); //横坐标和垂直半径对称
for i:=0 to Length(Vertexes)-1 do //上半圆整个沿水平直径再翻一次
AddVertex(Point(Vertexes[i].X,2*r-Vertexes[i].Y-CurL));
Label2.Caption:=Format('实际用了 %d 个小正方形(边长%d)',[Length(Vertexes),CurL]);
DrawState:=true;
PaintBox1.Invalidate;
end;
#29
有两种对称形状,一种是圆点是一个格子中间的,另一种是圆点是四个格子交界的。
#30
多谢了