C# 缩放绘图视觉算法
我正在尝试实现一种算法,该算法将找到最佳比例系数和最佳角度来定位图形,使其不与容器边缘重叠,并采用最佳角度(由图形尽可能宽的角度定义)。我使用a来表示图形 我现在想到的是一个暴力检查,看起来像这样:C# 缩放绘图视觉算法,c#,algorithm,C#,Algorithm,我正在尝试实现一种算法,该算法将找到最佳比例系数和最佳角度来定位图形,使其不与容器边缘重叠,并采用最佳角度(由图形尽可能宽的角度定义)。我使用a来表示图形 我现在想到的是一个暴力检查,看起来像这样: set scale to 1; while (overlaps with end points(in set (verticies) { !exists vertex which position.x > window.width && position.y > wind
set scale to 1;
while (overlaps with end points(in set (verticies) { !exists vertex which position.x > window.width && position.y > window.height && position.X < 0 && position.Y < 0)){
for 0 : 360 {
check whether at this angle all the points are aligned correctly,if yes
save the result as the last valid tuple(angle and scale) and continue
}
increase scale by a constant
}
将比例设置为1;
而(与端点重叠(在集合(垂直方向){!中存在位置.x>window.width&&position.y>window.height&&position.x<0&&position.y<0的顶点)){
0:360{
检查是否在此角度下所有点都正确对齐(如果是)
将结果保存为最后一个有效元组(角度和比例),然后继续
}
将比例增加一个常数
}
如果有人知道这样一个实现已经在网上提供,请一定要与我分享,否则请告诉我你对我目前的想法的看法
<>编辑:你可以一直认为图的中心点位于屏幕的中心。 < P>这是你试图找出的 那么答案(弧度)是
检查哪个
Math.Abs(θ)
最小,以获得最终答案。编辑我编辑了这篇文章并提出了另一个解决方案
不太清楚“图形”和“容器”的边缘是什么。我假设容器是一种画布,表面是一个轴对齐的矩形
然后,您可以通过三个步骤拟合图形:
- 当然,这取决于你的图形的性质,但是如果你的图形已经是一个多边形,这就像扔掉所有凹点一样简单
- 找到最佳旋转角度,如下所示。(我之前曾建议使用该算法找到面积最小的封闭矩形,但这并没有给出最佳解决方案。)
- 通过缩放和平移旋转的图形,使其适合您的容器
- 不必连续增加比例;一旦找到最佳角度,就可以轻松地从旋转图形的边界框和容器的尺寸计算比例
- 您不需要测试360°以下的所有角度。检查四分之一圆就足够了:如果ϑ是一个解,那么ϑ+180°是同一个解,只是旋转。您可以通过检查高度和宽度交换的ϑ-90°边界框来检查90°到180°范围内的解
- 通过以一阶步长探测解的范围,你只能得到一个粗略的解。更好的方法可能是用递减的角度步长探测更小的角度范围。(您可以根据所需的精度和性能拟合搜索间隔的精确值。性能应该可以,因为凸包通常只有几个点。)
- 无需围绕屏幕中心旋转。只需围绕原点旋转,并在最后一步使多边形适合容器
/*
*返回多边形的左、右、顶和底点
*/
函数边界(多边形){
bx={
左:多边形[0],
右:多边形[0],
顶部:多边形[0],
底部:多边形[0]
};
对于(变量i=1;ibx.right.x)bx.right=p;
如果(p.ybx.bottom.y)bx.bottom=p;
}
返回bx;
}
/*
*返回变换(旋转、缩放、偏移)的多边形
*/
函数变换(多边形、deg、scale、dx、dy){
var phi=数学PI*deg/180;
var c=数学cos(φ);
var s=数学sin(φ);
var-rot=[];
对于(变量i=0;i0.002;d*=0.1){
var a=选择角;
对于(变量i=a-9*d;i// Width W is the limit
θ = Math.Atan(h/w)+Math.Acos(W/Math.Sqrt(h*h+w*w));
// Height H is the limit (like picture)
θ = Math.Asin(H/Math.Sqrt(h*h+w*w))-Math.Atan(h/w);
/*
* Return left, right, top and bottom points of a polygon
*/
function bounds(poly) {
bx = {
left: poly[0],
right: poly[0],
top: poly[0],
bottom: poly[0]
};
for (var i = 1; i < poly.length; i++) {
var p = poly[i];
if (p.x < bx.left.x) bx.left = p;
if (p.x > bx.right.x) bx.right = p;
if (p.y < bx.top.y) bx.top = p;
if (p.y > bx.bottom.y) bx.bottom = p;
}
return bx;
}
/*
* Return a transformed (rotated, scaled, offset) polygon
*/
function transform(poly, deg, scale, dx, dy) {
var phi = Math.PI * deg / 180;
var c = Math.cos(phi);
var s = Math.sin(phi);
var rot = [];
for (var i = 0; i < poly.length; i++) {
var p = poly[i];
var x = scale * (c * p.x - s * p.y + dx);
var y = scale * (s * p.x + c * p.y + dy);
rot.push(new Pt(x, y));
}
return rot;
}
/*
* Return a polygon rotated by deg degrees.
*/
function rotate(poly, deg) {
return transform(poly, deg, 1, 0, 0);
}
/*
* Assess a rotation of the polygon and update the optimum
* solution so far if necessary.
*/
function assess(opt, poly, angle, ratio) {
var rot = rotate(poly, angle);
var box = bounds(rot);
var w = box.right.x - box.left.x;
var h = box.bottom.y - box.top.y;
var r = w / h;
if (Math.abs(r - ratio) < opt.delta) {
opt.delta = Math.abs(r - ratio);
opt.angle = angle;
opt.width = w;
opt.height = h;
opt.left = box.left.x;
opt.top = box.top.y;
}
if (Math.abs(1/r - ratio) < opt.delta) {
opt.delta = Math.abs(1/r - ratio);
opt.angle = angle + 90;
opt.width = h;
opt.height = w;
opt.left = -box.bottom.y;
opt.top = box.left.x;
}
}
/*
* Fit polygon inside a rectangle of width x height
*/
function fit(poly, width, height) {
var ratio = width / height;
var opt = { delta: 1.0e+30 };
for (var i = 0; i < 90; i += 10) assess(opt, poly, i, ratio);
for (d = 1; d > 0.002; d *= 0.1) {
var a = opt.angle;
for (var i = a - 9*d; i < a + 9.5*d; i += d) {
assess(opt, poly, i, ratio);
}
}
var sx = width / opt.width;
var sy = height / opt.height;
return transform(poly,
opt.angle, Math.min(sx, sy),
-opt.left, -opt.top);
}