我注意到,几个PDF注释应用程序( Acrobat、Blue离子束等)有一个围绕多边形创建云模式的算法:

当拖动这个多边形的顶点时,云模式将被重新计算:

请注意如何重新计算弧以环绕多边形。他们没有被拉伸或扭曲。无论用什么算法来定义这一点,似乎都是一个行业标准。几个PDF编辑器允许您创建这个编辑器,在每个编辑器中,云弧在拖动顶点时看起来都是一样的。
我正在尝试创建一个WPF示例应用程序来复制这个示例,但是我似乎找不到生成云模式的文档。
我非常流利的平面设计和2D编程,我有能力创建工具来拖动周围的顶点,但我需要帮助找出如何绘制这些弧线。它看起来像一个PathGeometry中的一系列PathGeometry。
,所以我的问题是,在多边形周围创建这些弧线的算法是什么?
或
在哪里可以找到这些行业标准的PDF模式、图纸和/或注释的文档?(云、箭头、边框等)
发布于 2016-01-06 08:16:15
你素描中的云只是画在每个多边形边缘的一系列圆圈,有一定的重叠。
绘制填充的基本云形状的一个简单方法是首先填充多边形,然后在填充多边形的顶部绘制圆圈。
当你想要用部分透明的颜色填充云彩时,这种方法就会变平,因为圆圈相互重叠和与基本多边形重叠将被绘制两次。它还会错过云曲线上的小卡通风格的超调。
绘制云的一个更好的方法是先创建所有的圆,然后确定每个圆与其下一个相邻圆的相交角。然后,您可以创建一个包含圆圈段的路径,您可以填充该路径。轮廓由独立的弧形组成,端角偏移较小。
在您的示例中,云弧之间的距离是静态的。通过使该距离变量和使多边形边可被该距离均匀整除,使得多边形顶点上的弧线重合是很容易的。
下面是JavaScript中的一个示例实现(没有多边形拖动)。我不熟悉C#,但我认为基本的算法是清楚的。代码是一个完整的网页,可以在支持画布的浏览器中保存和显示;我已经在Firefox中进行了测试。
绘制云的函数采用半径、弧距和超调(以度为单位)等选项。我还没有测试过像小多边形这样的退化情况,但是在极端情况下,算法应该只为每个多边形顶点画一个弧线。
多边形必须按顺时针方向定义。否则,云将更像是云层上的一个洞。如果街角没有任何艺术品的话,那将是一个很好的特征。
编辑:我为下面的云算法提供了一个简单在线测试页面。该页面允许您使用各种参数。同时也很好地说明了该算法的不足。(在FF和Chrome中测试)
当开始角和结束角没有被正确地确定时,就会产生人工制品。与非常钝的角度,也可能有交叉之间的弧线旁边的角落。我没有解决这个问题,但我也没有考虑太多。)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Cumulunimbus</title>
<script type="text/javascript">
function Point(x, y) {
this.x = x;
this.y = y;
}
function get(obj, prop, fallback) {
if (obj.hasOwnProperty(prop)) return obj[prop];
return fallback;
}
/*
* Global intersection angles of two circles of the same radius
*/
function intersect(p, q, r) {
var dx = q.x - p.x;
var dy = q.y - p.y;
var len = Math.sqrt(dx*dx + dy*dy);
var a = 0.5 * len / r;
if (a < -1) a = -1;
if (a > 1) a = 1;
var phi = Math.atan2(dy, dx);
var gamma = Math.acos(a);
return [phi - gamma, Math.PI + phi + gamma];
}
/*
* Draw a cloud with the given options to the given context
*/
function cloud(cx, poly, opt) {
var radius = get(opt, "radius", 20);
var overlap = get(opt, "overlap", 5/6);
var stretch = get(opt, "stretch", true);
// Create a list of circles
var circle = [];
var delta = 2 * radius * overlap;
var prev = poly[poly.length - 1];
for (var i = 0; i < poly.length; i++) {
var curr = poly[i];
var dx = curr.x - prev.x;
var dy = curr.y - prev.y;
var len = Math.sqrt(dx*dx + dy*dy);
dx = dx / len;
dy = dy / len;
var d = delta;
if (stretch) {
var n = (len / delta + 0.5) | 0;
if (n < 1) n = 1;
d = len / n;
}
for (var a = 0; a + 0.1 * d < len; a += d) {
circle.push({
x: prev.x + a * dx,
y: prev.y + a * dy,
});
}
prev = curr;
}
// Determine intersection angles of circles
var prev = circle[circle.length - 1];
for (var i = 0; i < circle.length; i++) {
var curr = circle[i];
var angle = intersect(prev, curr, radius);
prev.end = angle[0];
curr.begin = angle[1];
prev = curr;
}
// Draw the cloud
cx.save();
if (get(opt, "fill", false)) {
cx.fillStyle = opt.fill;
cx.beginPath();
for (var i = 0; i < circle.length; i++) {
var curr = circle[i];
cx.arc(curr.x, curr.y, radius, curr.begin, curr.end);
}
cx.fill();
}
if (get(opt, "outline", false)) {
cx.strokeStyle = opt.outline;
cx.lineWidth = get(opt, "width", 1.0);
var incise = Math.PI * get(opt, "incise", 15) / 180;
for (var i = 0; i < circle.length; i++) {
var curr = circle[i];
cx.beginPath();
cx.arc(curr.x, curr.y, radius,
curr.begin, curr.end + incise);
cx.stroke();
}
}
cx.restore();
}
var poly = [
new Point(250, 50),
new Point(450, 150),
new Point(350, 450),
new Point(50, 300),
];
window.onload = function() {
cv = document.getElementById("cv");
cx = cv.getContext("2d");
cloud(cx, poly, {
fill: "lightblue", // fill colour
outline: "black", // outline colour
incise: 15, // overshoot in degrees
radius: 20, // arc radius
overlap: 0.8333, // arc distance relative to radius
stretch: false, // should corner arcs coincide?
});
}
</script>
</head>
<body>
<canvas width="500" height="500" id="cv"></canvas>
</body>
</html>https://stackoverflow.com/questions/34623855
复制相似问题