关于:矩形旋转和拟合

时间:2009-06-02 20:55:01

标签: algorithm math

辛苦工作后,我的大脑停止服务..(土耳其时间是晚上11点40分)

我正在做轮换工作。:

变量:

_cx = horizontal center of rect
_cy = vertical center of rect
_cos = cos value of current angle
_sin = sin value of current angle

to rotating any point in this rect :

function getx(x, y)
{
      return _cx + _cos * (x - _cx) - _sin * (y - _cy);
}
function gety(x, y)
{
      return _cy + _sin * (x - _cx) + _cos * (y - _cy);
}

我正在尝试在旋转过程之前调整给定矩形的大小以适应原始边界的最大尺寸..我该怎么办?

感谢您的进步

编辑:Igor Krivokon的解决方案

问题由Igor Krivokon解决,这是该解决方案的修改版本,适用于每个角度值

var h1:Number, h2:Number, hh:Number, ww:Number,
    degt:Number, d2r:Number, r2d:Number, deg:Number,
    sint:Number, cost:Number;
//@angle = given angle in radians
//@r is source/target rectangle
//@d2r is static PI / 180 constant for degree -> radian conversation
//@r2d is static 180 / PI constant for radian -> degree conversation
d2r = 0.017453292519943295769236907683141;
r2d = 57.295779513082320876798154814105;
deg = Math.abs(angle * r2d) % 360;
if(deg < 91)
{
    degt = angle;
}else if(deg < 181){
    degt = (180 - deg) * d2r;
}else if(deg < 271){
    degt = (deg - 180) * d2r;
}else{
    degt = (360 - deg) * d2r;
}

sint = Math.sin(degt);
cost = Math.cos(degt);

h1 = r.height * r.height / (r.width * sint + r.height * cost);
h2 = r.height * r.width / (r.width * cost + r.height * sint);
hh = Math.min(h1, h2);
ww = hh * r.width / r.height;
r.x = (r.width - ww) * .5;
r.y = (r.height - hh) * .5;
r.height = hh;
r.width = ww;

由于

4 个答案:

答案 0 :(得分:5)

如果您的原始尺寸为h和w,并且您转动的角度为phi,请尝试计算新的高度

h1 = h*h / (w*sin(phi) + h*cos(phi))

h2 = h*w / (w*cos(phi) + h*sin(phi))

选择hew height h'作为h1和h2中的最小值。

然后,显然,新宽度w' = h' * w / h

请尝试一下 - 我没有时间测试我的数学:)

答案 1 :(得分:0)

将rect分成4个较小的矩形。对角切割半边(旋转前,从角落到中心点),你将有8个三角形。你只需要4个。旋转后,这些三角形的斜边将突出原始边界框。

确定斜边的公式(你有原始角度,45,-45,135,-135和起点,这样mx + b),转换这些线(通过添加旋转来修改它们的斜率) ,将这些线与边界墙相交(y = 0,y = w,x = 0,x = h,距离公式,无限情况下的测试)&amp;弄清楚哪个斜边是最短的(从中心到墙壁,在拐角处)。由于所有的斜边都是相同的长度,所以只需将它们全部调整为这个新值,就可以得到新的矩形。

我做得对吗?

答案 2 :(得分:0)

function resize_factor()
{
    /* Find how far the upper-left corner sticks up beyond the top */
    overtop = gety(0, 0);
    /* Compute a vertical resize factor that would put that point at the top */
    /* (be sure to use floating point arithmetic) */
    vertical_resize = _cy / (_cy - overtop);

    /* Do the same for the lower-left corner sticking out beyond the left */
    /* (using 2*_cy for the height of the rectangle) */
    overleft = getx(0, 2*_cy);    
    horizontal_resize = _cx / (_cx - overleft);

    /* Return whichever resize constraint is stricter */
    return min(vertical_resize, horizontal_resize);
}

function resize_x(x)
{
    /* To get location of a point, after resize, before rotation... */
    /* ...multiply its resize factor by its distance from the center. */
    return resize_factor()*(x - _cx) + _cx;
}

function resize_y(y)
{
    return resize_factor()*(y - _cy) + _cy;
}

/* These resized coordinates can be used inside any other code you want: */
function getx_after_resize_and_rotate(x, y)
{
    return getx( resized_x(x), resized_y(y) );
}

注意:此代码假定角度顺时针旋转小于90度(因为这是图片显示的内容)。如果您的角度是其他角度,您可能需要检查所有4个角并确定哪些是最远的超越和过度。

答案 3 :(得分:0)

    fitRect: function( rw,rh,radians ){
            var x1 = -rw/2,
                x2 = rw/2,
                x3 = rw/2,
                x4 = -rw/2,
                y1 = rh/2,
                y2 = rh/2,
                y3 = -rh/2,
                y4 = -rh/2;

            var x11 = x1 * Math.cos(radians) + y1 * Math.sin(radians),
                y11 = -x1 * Math.sin(radians) + y1 * Math.cos(radians),
                x21 = x2 * Math.cos(radians) + y2 * Math.sin(radians),
                y21 = -x2 * Math.sin(radians) + y2 * Math.cos(radians), 
                x31 = x3 * Math.cos(radians) + y3 * Math.sin(radians),
                y31 = -x3 * Math.sin(radians) + y3 * Math.cos(radians),
                x41 = x4 * Math.cos(radians) + y4 * Math.sin(radians),
                y41 = -x4 * Math.sin(radians) + y4 * Math.cos(radians);

            var x_min = Math.min(x11,x21,x31,x41),
                x_max = Math.max(x11,x21,x31,x41);

            var y_min = Math.min(y11,y21,y31,y41);
                y_max = Math.max(y11,y21,y31,y41);

            return [x_max-x_min,y_max-y_min];
        }