C# 缩放绘图视觉算法

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

我正在尝试实现一种算法,该算法将找到最佳比例系数和最佳角度来定位图形,使其不与容器边缘重叠,并采用最佳角度(由图形尽可能宽的角度定义)。我使用a来表示图形

我现在想到的是一个暴力检查,看起来像这样:

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°范围内的解

  • 通过以一阶步长探测解的范围,你只能得到一个粗略的解。更好的方法可能是用递减的角度步长探测更小的角度范围。(您可以根据所需的精度和性能拟合搜索间隔的精确值。性能应该可以,因为凸包通常只有几个点。)

  • 无需围绕屏幕中心旋转。只需围绕原点旋转,并在最后一步使多边形适合容器

下面是一个Javascript实现(您要求使用C#,但我不熟悉这一点。不过,将此代码应用于其他语言应该不会有问题)

/*
*返回多边形的左、右、顶和底点
*/
函数边界(多边形){
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);
}