两个图形重合的问题(200分)

  • 主题发起人 主题发起人 马晓光
  • 开始时间 开始时间

马晓光

Unregistered / Unconfirmed
GUEST, unregistred user!
各位智者:
我想实现这个功能:画两个图形,如果出现交叉,那么:

1.去掉交叉部分,只连接外围轮廓,成为一个新的图形。
2.只保留交叉部分,并且连接它,成为一个新的图形。
3.将第二个图形去掉,并且去掉它所交叉的第一个图形的区域,
使第一个图形出现缺损。

这个功能类似PhotoShop中多个选区在不同的模式下出现的不同的形状的功能。
我是想先将矩形、圆角矩形、椭圆转化成Polygon后,用两个Polygon来实现上述功能,
再把融合后的图形转换成Polygon。我发现Delphi自带的
MS SDK Help Files的Win32 Programmer’s Reference中有几个API函数好像有可能
实现我说的功能。它们是BeginPath、EndPath、SelectClipPath、StrokePath……
但是我研究了好长时间也没有成功,各位智者有和良策?用以上函数行吗?不行,
该怎么办?
谢谢!
 
主要在于两个图形的交叉部分如何重叠成一个新的图形,用什么算法。
不交叉的、要去掉的都好办。
 
我的一点想法:
如果是bmp,那么把两个图形 A,B 用两个同样大的0-1矩阵 A,B表示,
1表示图形内部,0表示外部,这两个矩阵作逻辑与(就是&&,相信都清楚)运算,
得到的矩阵就是重叠的部分,记为C
这步解决了,相信你的问题就搞定了,其实就是[:)]在0-1矩阵中运用逻辑运算[:)]
当然0-1矩阵要一样大的,否则不能运算
这样的方法是很精确的!!!
1.去掉交叉部分,只连接外围轮廓,成为一个新的图形。
A,B取或运算 然后 与对C取反后的矩阵作与 就得到了
就是 (A OR B) AND ( NOT C)
2.只保留交叉部分,并且连接它,成为一个新的图形。
就是矩阵C=A AND B
3.将第二个图形去掉,并且去掉它所交叉的第一个图形的区域,使第一个图形出现缺损。
就是 A AND ( NOT B)
 
Haha..., 您好!

可不可以写一点代码做一个示范?我对矩阵不明白,一直没有形成概念。我是
用这个办法记忆Polygon的各个点的:

VAR
PolygonPs : array of TPoint

如果有两个矩形,将它们转换成Polygon,如下所示:

VAR
Rect1StartP : TPoint;
Rect1EndP : TPoint;
Rect2StartP : TPoint;
Rect2EndP : TPoint;

Polygon1 : array of TPoint;
Polygon2 : array of TPoint;

procedure RectToPolygon;
begin
SetLength(Polygon1, 0);
SetLength(Polygon1, High(Polugon1) + 2);
Polygon1[High(Polygon1)] := Rect1StartP;
SetLength(Polygon1, High(Polugon1) + 2);
Polygon1[High(Polygon1)] := Point(Rect1EndP.X, Rect1StartP.Y);
SetLength(Polygon1, High(Polugon1) + 2);
Polygon1[High(Polygon1)] := Rect1EndP;
SetLength(Polygon1, High(Polugon1) + 2);
Polygon1[High(Polygon1)] := Point(Rect1StartP.X, Rect1EndP.Y);
SetLength(Polygon1, High(Polugon1) + 2);
Polygon1[High(Polygon1)] := Rect1StartP; // 首尾相连

SetLength(Polygon2, 0);
SetLength(Polygon2, High(Polugon2) + 2);
Polygon2[High(Polygon2)] := Rect2StartP;
SetLength(Polygon2, High(Polugon2) + 2);
Polygon2[High(Polygon2)] := Point(Rect2EndP.X, Rect2StartP.Y);
SetLength(Polygon2, High(Polugon2) + 2);
Polygon2[High(Polygon2)] := Rect2EndP;
SetLength(Polygon2, High(Polugon2) + 2);
Polygon2[High(Polygon2)] := Point(Rect2StartP.X, Rect2EndP.Y);
SetLength(Polygon2, High(Polugon2) + 2);
Polygon2[High(Polygon2)] := Rect2StartP; // 首尾相连
end;

得到的两个Polygon如何操作? 不知你说的矩阵是这样的吗?
你说必须两个矩阵大小一样,但是如果任意两个多边形,
它们的点数不同,如何重合呢?矩形和椭圆在转换成Polygon 后,
两个Polygon中的项目数(就是点数)一定不同,这又怎么办呢?
另外 SetLength(Polygon, 0) 是不是就清空了这个Polygon了?

希望再多讲解一下好吗?最好有代码示范。谢谢!
 
to 马晓光:
我可能没有太说清楚,你再看一下:
把两个图形 A,B 放到两个同样大的0-1矩阵 A,B表示,
1表示图形内部,0表示外部
有点象photoshop中图层的意思

00000000000000
00111111110000
00111111110000
00111111110000
00111111110000
00000000000000
这个矩阵表示一个矩形

00001110000000
00011111100000
00111111110000
00111111110000
00011111100000
00011110000000
这个矩阵表示一个椭圆.

两个矩阵作and,or ......,就是他们对应的元素作and,or...








 
我太菜了!回去好好研究一下,Haha兄的分是少不了的。
请稍等。可能我还会向您请教!非常感谢!
 
呵,这就是矢量图形的逻辑操作,介绍你一个网站,有C的源代码下载,你一进入它的页面,
看见那个操作的英国地图你就会大喊:这就是我要的!它不光有减,还有加、取反、Merge、和Union
等操作

我已经在VC中调通了,要的话吱一声。

http://www.cs.man.ac.uk/aig/staff/alan/software/
 
To Haha...

你的方法我试过了,确实不错,用它来判断两个图形是否交叉很有效。
但是两个图形的边框和内部在矩阵中都是1,如果两个矩阵作AND、OR,计算
出来的新的图形的边框和内部在矩阵中还是1。如果我只想要矩阵中图形边框的
1,然后将这些1所对应的坐标点依次加入一个数组中,比如:

var
Polygon: array of TPoint;
begin
SetLength(Polygon, 0);
SetLength(Polygon, High(Polygon) + 2);
Polygon[High(Polygon)] := Point(1, 1);
end;

其中1代表矩阵中的值对应到Image.Canvas中的坐标X、Y。这样就可得到一个多边形
选区。但是矩阵中那么多的1,如何只提取外围轮廓的1呢?并且还要依次加入Polygon
中,以形成一个首尾相连的多边形。

我其实就是想实现Photoshop中的选区功能,就是Marquee Tools。做单一选区,
还好办,多个选区就遇到上述麻烦了。比如在Photoshop中选中任何一个marquee tools,
比如lasso tool(套索)工具后,就出现一个相应的工具条,其中有如下几个按钮:
'New Selection'、'Add To Selection'、'Subtract From Selection'、
'Intersect With Selection' 。假如在'Add To Selection'下,用Lasso画了
两个多边形选区,一旦交叉就会重合为一个新的大多边形,
但是新多边形只是连接两个Lasso的外围边框,交叉重叠的部分就去掉了。
关键如何连接这些外围的点?其它选项以此类推。
(我用的是英文的Photoshop6.0)。

望指教!谢谢!

To 吕雪松

您好,您说的C代码可不可以转换成Pascal,或者是我的C++Builder能编译吗?
这些代码可以解决我的问题吗?如果一上都满足,请您将代码发到
maxiaoguang10000@sina.com
不胜感谢!
 
to 马晓光:
计算机中的点都是离散的,如果用数组来存储一个图形的边缘的话,必须保证这些
点是连续的,这样处理起来不方便,也容易出错,其实选取区也可以用相同的方式(矩阵)来处理
(存储和运算),而且选取本身需要精确.用边缘点操作的话很难保证这一点的.关键是当用户
创选取区的时候你要从边缘点得到整个图形(也就是选区),如果选区只有矩形的话很容易,
但如果有不规则选区,那么从边缘点得到整个图形就需要在好好考虑一下.
找边缘点的方法是这样的(不要嫌烦),你看网格子,附件的画图,你先画一个图,放大到能看到
像素,显示网格子:
你可以看到两个像素(格子)相邻的话,把其中一个看做是固定的,另外一个有8个位置(图中0的位置)
000 (i,j)对应的8个位置 (i,j+1) (i+1,j)................
010
000
而边缘必然要求点点相邻成为一条连续的封闭线,则你要判断相邻的8个点中,哪个是内点,
哪个是边缘点,边缘点的充要条件是他的相邻点中至少有一个是空的(就是=0),而内点的相邻
点必然全非空(=1),你先找一个边缘点,依次沿一个方向搜索直到得到的边缘点是已经得到
的,说明已经的到一个封闭曲线,我想这个算法最好用一个递归实现(当然用循环也可以实现)

有一点要注意的是能用矩阵的情况下还是用矩阵.先进行矩阵运算(or)得到连接图形,再用
上面的方法取出边缘




 
to 马晓光:
看了你的自我介绍,我很感动,也很佩服!!
 
to 吕雪松:
我想要你在VC中的程序,可以EMAIL 给我吗?
t163t163@163.net
 
to Haha...
谢谢你,我们交个朋友好吗?你的回答,我们还得研究研究,稍等!
不知怎样才能查到吕雪松的E-Mail地址,请指教。谢谢!
 
to 马晓光:
吕雪松的E-Mail我也不知道亚
我的qq和email是公开的,你快加我亚
 
已经发给Haha和t163t163了,是VC的代码,退出时会有一些内存泄漏,但算法已经实现,
我就没去管它了。
 
to Haha..

非常感谢这些日子你详细、耐心的讲解,使我受益匪浅。
用矩阵判断两个图形是否重合和得到一个新的图形确实是一个非常好的方法。
至于如何将新的图形的边框找出来,也确实是个值得好好研究的问题,
至今我也没有想明白。你上次说的方法很有用,
但是究竟按照什么样的算法才能精确地算出边框中相连的点,
用递归,我不会,循环我还得想一想。通过这些日子的探讨,我有所提高,
了解了矩阵的用法,也从你那儿学到了编程的思维方式。我想先结束这个话题的讨论,
选区功能剩下的问题,我再研究研究。

我的邮箱是:maxiaoguang10000@sina.com
如果以后你有了更好的发现,可以再和我联系吗?
另外,如果你知道好的PDF格式的电子书下载的链接或网站,
请您告诉我好吗?我正在找关于“颜色学”的书。谢谢!

to 吕雪松

谢谢你, 我已经收到了你的邮件。
 
To 吕雪松,
能发一份么?zhaodongxu@yahoo.com.cn
 

Similar threads

D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部