在反向Y轴上绘制文本

时间:2014-09-28 05:48:01

标签: c# .net winforms drawing gdi+

我正在编写一个可视化工具应用程序:它从XML加载构建几何体并在屏幕上绘制它。 建筑物由矩形房间组成,其中许多房间 - 所以我想在它们上面绘制它们的名字。

我使用this教程在我的表单中翻转Y轴,因为构建存储在笛卡尔坐标中的数据。并将所有这些转换为经典的Windows" y逐渐减少"系统虽然绘图看起来很奇怪。
我还需要扩展和翻译我的场景"到左下角。
而且,我最后的痛苦,我需要再次翻转我的文本 - 因为它也会翻转!

正如tutorial所说,我需要:

  1. 翻转Y轴,缩放并将场景移动到所需位置
  2. 以笛卡尔坐标绘制建筑物几何图形(只是矩形)
  3. 回到" Y长大"系统,规模和再次移动
  4. 在此"经典"中绘制文字系统
  5. 但是文字的坐标无效!
    它们从正确的位置向下移动:(

    所以这是我的问题 - 如何正确计算Windows窗体对象中的新文本坐标

    void VisualizerForm_Paint(object sender, PaintEventArgs e)
    {
        // Setup graphics output settings
        var g = e.Graphics;
        g.Clear(Color.White);
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        g.PageUnit = GraphicsUnit.Pixel;
    
        // Move coordinate system center to the bottom left corner,
        // scale it to user-defined scale value and flip Y axis (mul it scale to -1)
        g.ScaleTransform(m_scale, -m_scale, MatrixOrder.Append);
        g.TranslateTransform(50, Height - 50, MatrixOrder.Append);
    
        // ... Draw some complex building geometry ...
    
        // Draw building room
        var customPen = new Pen(Color.Black, 1.0f / g.DpiX);
        var rect = new RectangleF(box.X1, box.Y1, (box.X2 - box.X1), (box.Y2 - box.Y1));
        g.DrawRectangle(customPen, box.X1, box.Y1, (box.X2 - box.X1), (box.Y2 - box.Y1));
    
        GraphicsState gs = g.Save();
    
        // First reset transform matrix
        g.ResetTransform();
        // Then again scale and move scene, but now with classic down-incresed Y axis
        g.ScaleTransform(m_scale, m_scale, MatrixOrder.Append);
        g.TranslateTransform(50, Height - 50, MatrixOrder.Append);
    
        // All Y coords now must be inverted :/ *sigh*
        box.Y1 *= -1.0f;
        box.Y2 *= -1.0f;
        rect = new RectangleF(box.X1, box.Y1, Math.Abs(box.X2 - box.X1), Math.Abs(box.Y2 - box.Y1));
    
        // FIXME: This text is drawing in incorrect place
        var fnt = new Font("Arial", 40f / g.DpiX, FontStyle.Bold, GraphicsUnit.Pixel);
        g.DrawString("ID: " + box.Id, fnt, Brushes.Black, rect, stringFormat);
    
        g.Restore(gs);
    }
    

2 个答案:

答案 0 :(得分:1)

试试这个:

void DrawDigonalString(Graphics G, string S, Font F, Brush B, PointF P, int Angle)
{
    SizeF MySize = G.MeasureString(S, F);
    G.TranslateTransform(P.X + MySize.Width / 2, P.Y + MySize.Height / 2);
    G.RotateTransform(Angle);
    G.DrawString(S, F, B, new PointF(-MySize.Width / 2, -MySize.Height / 2));
    G.RotateTransform(-Angle);
    G.TranslateTransform(-P.X - MySize.Width / 2, -P.Y- MySize.Height / 2);
}

答案 1 :(得分:1)

最后我明白了! 下面的类在其中心绘制带有指定文本的矩形 - 在Y反转场景内 文本自动缩放以适合实际的矩形大小。享受:)

class RectangleWithText
{
    RectangleF m_extent = new RectangleF();
    string m_text = "";

    Font m_textFont = null;
    RectangleF m_textRect = new RectangleF();

    public RectangleWithText( RectangleF extent, string text )
    {
        m_extent = extent;
        m_text = text;
    }

    public void Draw( Graphics g )
    {
        var dashedGrayPen = new Pen( Color.Gray, 1.0f / g.DpiX ) { DashStyle = DashStyle.Dash };
        var brownPen = new Pen( Color.Brown, 1.0f / g.DpiX );

        // Draw rectangle itself
        g.DrawRectangle( brownPen, m_extent.X, m_extent.Y, m_extent.Width, m_extent.Height );

        // Draw text on it
        var extentCenter = new PointF( ( m_extent.Left + m_extent.Right ) / 2, ( m_extent.Bottom + m_extent.Top ) / 2 );
        DrawText( g, m_text, extentCenter, m_extent );

        }
    }

    private void DrawText( Graphics g, string text, PointF ptStart, RectangleF extent )
    {
        var gs = g.Save();

        // Inverse Y axis again - now it grow down;
        // if we don't do this, text will be drawn inverted
        g.ScaleTransform( 1.0f, -1.0f, MatrixOrder.Prepend );

        if ( m_textFont == null )
        {
            // Find the maximum appropriate text size to fix the extent
            float fontSize = 100.0f;
            Font fnt;
            SizeF textSize;
            do
            {
                fnt = new Font( "Arial", fontSize / g.DpiX, FontStyle.Bold, GraphicsUnit.Pixel );
                textSize = g.MeasureString( text, fnt );
                m_textRect = new RectangleF( new PointF( ptStart.X - textSize.Width / 2.0f, -ptStart.Y - textSize.Height / 2.0f ), textSize );

                var textRectInv = new RectangleF( m_textRect.X, -m_textRect.Y, m_textRect.Width, m_textRect.Height );
                if ( extent.Contains( textRectInv ) )
                    break;

                fontSize -= 1.0f;
                if ( fontSize <= 0 )
                {
                    fontSize = 1.0f;
                    break;
                }
            } while ( true );

            m_textFont = fnt;
        }

        // Create a StringFormat object with the each line of text, and the block of text centered on the page
        var stringFormat = new StringFormat()
        {
            Alignment = StringAlignment.Center,
            LineAlignment = StringAlignment.Center
        };
        g.DrawString( text, m_textFont, Brushes.Black, m_textRect, stringFormat );

        g.Restore( gs );
    }
}