【问题标题】:Calculate the maximum available area after TranslateTransform计算 TranslateTransform 后的最大可用面积
【发布时间】:2014-06-18 13:21:31
【问题描述】:

假设我想在窗体内绘制一个有角度的矩形。

我可以这样做

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.RotateTransform(20);
        e.Graphics.DrawRectangle(Pens.Black, 0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
    }

但这只会旋转矩形,因此缺少左侧和底部。

但我真正想要实现的是,我想像这样在我的表单内绘制具有一定角度的最大可能矩形

最好的方法是什么?

【问题讨论】:

    标签: c# .net winforms drawing rectangles


    【解决方案1】:

    我们可以找到与所有四个边相交的角度为 θ 的矩形。如果我们让 W,H 是我们窗口的宽度和高度,那么角度是预先已知的弧度。现在让 a, b 是我们试图放入盒子中的矩形的宽度和高度,这是我们希望找到的两个值。令 x0,y0 为窗口中心点的坐标 x0=W/2, y0=H/2。矩形的一个角将是

    x1 = x0 - 0.5 * a * sin(th) + 0.5 * b * cos(th)
    y1 = y0 + 0.5 * a * cos(th) + 0.5 * b * sin(th)
    

    另一点相似,但符号不同。一点三角函数就会显示这一点。

    让矩形接触我们想要的边

    a * sin(th) + b cos(th) = W
    a * cos(th) + b sin(th) = H
    

    这给了我们一对联立方程,我们可以求解。将第一个乘以 sin(th),第二个乘以 cos(th)

    a * sin(th) sin(th) + b cos(th) sin(th) = W sin(th)
    a * cos(th) cos(th) + b sin(th) cos(th) = H cos(th)
    

    减法

    a ( sin(th) sin(th) - cos(th) cos(th) ) = W sin(th) - H cos(th)
    

    除以 ( sin(th) sin(th) - cos(th) cos(th) ) 得到

    a = (W sin(th) - H cos(th)) / ( sin(th) sin(th) - cos(th) cos(th) )
    

    类似的过程给出

    b = (H sin(th) - W cos(th)) / ( sin(th) sin(th) - cos(th) cos(th) )
    

    一旦我们有了 a 和 b,我们就可以计算矩形的角并绘制它。

    我已将代码放在 jsfiddle http://jsfiddle.net/SalixAlba/5jcT7/ 中,代码是

    // canvas and mousedown related variables
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var $canvas = $("#canvas");
    var canvasOffset = $canvas.offset();
    var offsetX = canvasOffset.left;
    var offsetY = canvasOffset.top;
    var scrollX = $canvas.scrollLeft();
    var scrollY = $canvas.scrollTop();
    // save canvas size to vars b/ they're used often
    var W = canvas.width;
    var H = canvas.height;
    
     var spinner = $( "#startAng" ).spinner({ 
      spin: function( event, ui ) {
        if ( ui.value > 180 ) {
          $( this ).spinner( "value", ui.value - 360 );
            draw();
          return false;
        } else if ( ui.value < -180 ) {
          $( this ).spinner( "value", ui.value + 360 );
            draw();
          return false;
        }
        draw();
      }
    });
    
    
    var angle = 10.0;
    
    function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    angle = $("#startAng").spinner("value");
    var th = Math.PI*angle/180.0;
    var S = Math.sin(th);
    var C = Math.cos(th);
    var S2 = S*S - C*C;
    var a = (W*S-H*C)/S2;
    var b = (H*S-W*C)/S2;
    var x0 = W/2;
    var y0 = H/2;
    //alert("angle "+angle+"S "+S+" "+C+" "+a+" "+b);
    var x1 = x0 - 0.5 * a * Math.sin(th) + 0.5 * b * Math.cos(th);
    var y1 = y0 + 0.5 * a * Math.cos(th) + 0.5 * b * Math.sin(th);
    
    var x2 = x0 - 0.5 * a * Math.sin(th) - 0.5 * b * Math.cos(th);
    var y2 = y0 + 0.5 * a * Math.cos(th) - 0.5 * b * Math.sin(th);
    
    var x3 = x0 + 0.5 * a * Math.sin(th) + 0.5 * b * Math.cos(th);
    var y3 = y0 - 0.5 * a * Math.cos(th) + 0.5 * b * Math.sin(th);
    
    var x4 = x0 + 0.5 * a * Math.sin(th) - 0.5 * b * Math.cos(th);
    var y4 = y0 - 0.5 * a * Math.cos(th) - 0.5 * b * Math.sin(th);
    
    ctx.beginPath();
    ctx.moveTo(x1,y1);
    ctx.lineTo(x2,y2);
    ctx.lineTo(x4,y4);
    ctx.lineTo(x3,y3);
    ctx.lineTo(x1,y1);
    ctx.closePath();
    ctx.stroke();
    }
    
    $( ".ui-spinner-input" ).on( "spinchange", draw );
    $( ".ui-spinner-input" ).on( "spinstop", draw );
    $( "#baseRad" ).on( "spin", draw );
    
    draw();
    

    请注意,这不一定给出最大的矩形,因为可能有更大的矩形接触两侧,而且可能的角度也有一些限制。

    【讨论】:

      【解决方案2】:

      我做了一些草图来解决这个问题。问题更多是关于数学而不是编程,但这是我的想法。我在绘画中做过,但尝试跟随:

      旋转矩形时,需要为它计算newWidthnewHeight。制作一个具有这些尺寸的新矩形,并将其放在左上角,就像您当前的矩形一样。 alpha α 代表您要旋转的度数。旋转后,您需要将这个新矩形向右移动,即X 的数量。然后,您将尽可能大的矩形完美地定位在您的绘图区域。

      以下是代码的一些想法。我还没有测试过:

      private void Form1_Paint(object sender, PaintEventArgs e)
          {
              double angle = 20;
      
              double width = Convert.ToDouble(e.ClipRectangle.Width),
                     height = Convert.ToDouble(e.ClipRectangle.Height),
                     h = Math.Sqrt((width*width) + (height*height)),
                     y = (width/h);
      
              int newHeight = Convert.ToInt32(height*y),
                  newWidth = Convert.ToInt32(width*y),
                  x = Convert.ToInt32((Math.Sin(angle) * height);
      
              e.Graphics.RotateTransform(angle);
              e.Graphics.DrawRectangle(Pens.Black, x, 0, newWidth, newHeight);
          }
      

      【讨论】:

        猜你喜欢
        • 2011-08-12
        • 2019-11-05
        • 2015-01-16
        • 2011-06-07
        • 2018-01-09
        • 2018-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多