这个问题我很难解释,所以我将用一些图像和文本进行说明。
对于一台钢制雕刻机,我需要使用.NET的普通图形框架来创建一个发送到雕刻机的"文档"——它就像普通打印机一样被处理。有问题的机器是这样的:
http://www.rolanddga.com/products/impactprinters/mpx90/features.asp
我可以用这个在C#中打印一个文本大纲:
// ALL UNITS ARE SET IN MILIMETERS (MM)
Graphics g = <instantiated from my printers-printpage-event>;
// The following values are set as "constants" here for the purpose of my question
// they normally are passed as parameters
string s = "ABC";
float fontSize = 4.0F;
RectangleF r = new RectangleF(0, 30.0F, 100.0F, 40.0F);
StringFormat sfDraw = new StringFormat();
sfDraw.Alignment = StringAlignment.Center;
FontStyle fStyle = FontStyle.Regular;
using (var gpDraw = new GraphicsPath())
{
gpDraw.AddString(text, fFamily, (int)fStyle, fSize, r, sfDraw);
SolidBrush brushFG = new SolidBrush(Color.Black);
Pen pen = new Pen(brushFG, 0.01F);
g.DrawPath(pen, gpDraw);
}
它给出类似于以下内容的输出:http://i47.tinypic.com/mruu4j.jpg
我现在想要的是填写这个大纲。不仅仅是使用笔刷填充(使用g.FillPath(brushFG,gpDraw)可以很容易地完成)。
相反,它应该用越来越小的轮廓"填充",如图所示:http://i46.tinypic.com/b3kb29.png
(不同的线条颜色仅用于使示例更清晰)。
当我在Photoshop中做这个例子时,我意识到我实际上想做的是模仿Photoshop的选择/修改/合同中的功能。
但我对如何做到这一点束手无策。
有什么帮助吗?我不是在寻找一个完整的解决方案,但我现在完全陷入了困境。我尝试过简单的缩放,这可能是错误的方式(因为它不能产生正确的结果…)
更新2012-07-16:我现在正在使用Clipper库http://www.angusj.com/delphi/clipper.php它有一个很棒的函数,叫做OffsetPolygons。
我的测试代码如下所示:http://pastie.org/4264890
它适用于"单个"多边形,例如"C",因为它只由单个多边形组成。"O"由两个多边形组成,一个是内部多边形,另一个是外部多边形。"A"也是如此。这些给我带来了一些麻烦。查看这些图像:
C:http://i46.tinypic.com/ap304.pngO:http://i45.tinypic.com/35k60xg.jpgA:http://i50.tinypic.com/1zyaibm.pngB:http://i49.tinypic.com/5lbb40.png
你得到了图片(呵呵…;-)
我认为问题是,当实际上有2个(在a和O的情况下),在B的情况下有3个时,我将GraphicsPath中的所有内容都提取为单个多边形。
Clipper的OffsetPolygons实际上采用了一个多边形阵列,所以我想它可以正确地做到这一点。但我不知道如何从GraphicsPath中提取路径作为单独的多边形。
更新2012-07-16(当天晚些时候):
好吧,我现在已经成功了,并将在回答中解释它,希望它能帮助其他有类似问题的人。
非常感谢一路上提供帮助的每一个人我接受自己答案的唯一原因是,其他人可能会从这个问题中获得完整的解决方案。
看看一种对多边形进行膨胀/收缩(偏移、缓冲)的算法——那里的提问者实际上是在询问反向操作,但那里的答案也适用于您的情况。其中一个(评分最高的)有一个指向C#版本的开源库的指针。
顺便说一句,您所描述的操作的常用名称是"多边形偏移"。
使用Clipper库只是战斗的一半。
我从GraphicsPath中提取了一个数组中的所有点,因此无意中创建了一个基于两个单独多边形的畸形多边形(在"a"的情况下)。
相反,我需要检查GraphicsPath上的PointTypes数组属性。每当一个点的PointType==0时,就意味着一个新多边形的开始。因此,提取方法应该使用这个,而不是返回一个多边形数组,而不仅仅是一个多边形:
private ClipperPolygons graphicsPathToPolygons(GraphicsPath gp)
{
ClipperPolygons polyList = new ClipperPolygons();
ClipperPolygon poly = null;
for (int i = 0; i < gp.PointCount; i++)
{
PointF p = gp.PathPoints[i];
byte pType = gp.PathTypes[i];
if (pType == 0)
{
if (poly != null)
polyList.Add(poly);
poly = new ClipperPolygon();
}
IntPoint ip = new IntPoint();
ip.X = (int)(p.X * pointScale);
ip.Y = (int)(p.Y * pointScale);
poly.Add(ip);
}
if (poly != null)
polyList.Add(poly);
return polyList;
}
Clipper的OffsetPolygons实际上想要一个多边形列表,所以这对我来说应该是显而易见的。
整个代码可以在这里看到:http://pastie.org/4265265
如果你好奇的话,我已经把整个测试项目压缩到这里,在VisualStudio中打开并编译。
http://gehling.dk/wp-content/uploads/2012/07/TestClipper.zip
它没有以任何方式针对速度进行优化。
/Carsten