C#之深入理解GDI+绘制圆弧及圆角矩形等比缩放的绘制

简介: GDI+中对于圆弧的绘制,是以给定的长方形(Rectangle`结构)为边界绘制的椭圆的一部分形成的圆弧。绘制的圆弧的中心为长方形内切椭圆的圆心(如果是正方形,则正方形的...

理解圆弧绘制

GDI+中对于圆弧的绘制,是以给定的长方形(System.Drawing.Rectangle 结构)为边界绘制的椭圆的一部分形成的圆弧。绘制的圆弧的中心为长方形内切椭圆的圆心(如果是正方形,则正方形的中心是内切圆的圆心)

Graphics对象的DrawArc()方法用于绘制圆弧线段;GraphicsPath对象的AddArc()方法用于绘制圆弧路径。

DrawArc为例,参数为:DrawArc (System.Drawing.Pen pen, System.Drawing.Rectangle rect, float startAngle, float sweepAngle),绘制一段弧线,它表示 Rectangle 结构指定的椭圆的一部分。

  • pen 为画笔对象。
  • rect 包含圆弧的长方体结构。
  • startAngle 圆弧绘制的开始角度。
  • sweepAngle 从 startAngle 角度到弧线的结束点沿顺时针方向度量的角(以度为单位),即从startAngle开始绘制弧线转动的角度。

新建Winform项目GDIForArc,测试和演示弧形绘制的效果。

直接看下面的代码,分别绘制矩形对应的四个角的弧形(1/4圆),可以很直观的看到圆弧的绘制及与长方体的关系:

protected override void OnPaint(PaintEventArgs e)
{
    Graphics g = e.Graphics;
    Pen pn = new Pen(Color.Blue,5);
    Rectangle rect = new Rectangle(50, 50, 150, 150);
    g.DrawRectangle(pn, rect);

    Rectangle rect2 = new Rectangle(300, 50, 150, 350);
    g.DrawRectangle(pn, rect2);

    // 红色 0-90deg的圆弧
    pn.Color = RedColor;
    g.DrawArc(pn, rect, 0, 90);

    g.DrawArc(pn, rect2, 0, 90);

    // 黑色 90-180deg的圆弧
    pn.Color = BalckColor;
    g.DrawArc(pn, rect, 90, 90);

    g.DrawArc(pn, rect2, 90, 90);

    // 绿色 180-270deg的圆弧
    pn.Color = GreenColor;
    g.DrawArc(pn, rect, 180, 90);

    g.DrawArc(pn, rect2, 180, 90);

    // 粉色 270-360deg的圆弧
    pn.Color = HotPink;
    g.DrawArc(pn, rect, 270, 90);

    g.DrawArc(pn, rect2, 270, 90);
}

从圆弧到绘制圆角长方体

GDI+中绘图系统中顺时针方向为旋转正方向,水平向右方向为x轴正方向,垂直向下为y轴正方向。

通过Rectangle结构内的四个圆弧,可以组合成四个圆角,从而可以进一步实现圆角长方体、圆形等图形。

如下,是使用这个方式绘制的圆角矩形。

需要注意的点:

  • 线条连接时的1像素问题,很多时候会出现1像素的间隔,并没有完全闭合连接,需要额外处理
  • Pen.LineJoin 指定线条连接点的模式
// 绘制圆角矩形
pn.Color = Color.MediumVioletRed;

// 指定连接处的连接点
pn.LineJoin = LineJoin.Round;

Rectangle roundRect = new Rectangle(500, 50, 150, 80);
var radius = 20;
var R = radius * 2;
Rectangle arcRect = new Rectangle(roundRect.X, roundRect.Y, R, R);

// 左上角
g.DrawArc(pn, arcRect, 180, 90);
// 右上角
arcRect.X = roundRect.Right - R;
g.DrawArc(pn, arcRect, 270, 90);
// 右下角
arcRect.Y = roundRect.Bottom - R;
g.DrawArc(pn, arcRect, 0, 90);
// 左下角
arcRect.X = roundRect.Left;
g.DrawArc(pn, arcRect, 90, 90);

#region 单独绘制线条,需要处理1像素间隔问题,且连接处不平滑
g.DrawLine(pn, roundRect.X + radius, roundRect.Y, roundRect.Right - radius + 1, roundRect.Y);

g.DrawLine(pn, roundRect.Right, roundRect.Y + radius, roundRect.Right, roundRect.Bottom - radius + 1);

g.DrawLine(pn, roundRect.Right - radius + 1, roundRect.Bottom, roundRect.Left + radius, roundRect.Bottom);

g.DrawLine(pn, roundRect.Left, roundRect.Bottom - radius + 1, roundRect.Left, roundRect.Y + radius);
#endregion

如何实现等比缩放绘制圆角矩形

按固定比例计算缩放矩形的尝试(不推荐)

根据上面绘制矩形的思路,想着同样实现一个按照等比缩放绘制内部圆角矩形的方式。主要思路是,指定一个缩放比例,让外部的矩形宽高、位置、圆角绘制的半径、直径等对应等比缩放并计算其值。

然后就是圆角矩形的绘制思路。

#region 等比缩放的绘制圆角矩形
//// 等比缩放,绘制内层圆角矩形
var scale = 0.8f;
var radiusScale = radius * scale;
var RScale = radiusScale * 2;
var innerRoundRect = new RectangleF(roundRect.X + (roundRect.Width - roundRect.Width * scale) / 2, roundRect.Y + (roundRect.Height - roundRect.Height * scale) / 2, roundRect.Width * scale, roundRect.Height * scale);
var arcRectScale = new RectangleF(innerRoundRect.X, innerRoundRect.Y, RScale, RScale);

//var scale = 0.8f;
//var radiusScale = Convert.ToInt32(radius * scale);
//var RScale = radiusScale * 2;
//var width = Convert.ToInt32(roundRect.Width * scale);
//var height = Convert.ToInt32(roundRect.Height * scale);
//var innerRoundRect = new Rectangle(roundRect.X + (roundRect.Width - width) / 2, roundRect.Y + (roundRect.Height - height) / 2, width, height);
//var arcRectScale = new Rectangle(innerRoundRect.X, innerRoundRect.Y, RScale, RScale);

pn.Color = Color.MediumPurple;
arcRectScale.X = innerRoundRect.X;
arcRectScale.Y = innerRoundRect.Y;

// 左上角
g.DrawArc(pn, arcRectScale, 180, 90);
g.DrawLine(pn, innerRoundRect.X + radiusScale, innerRoundRect.Y, innerRoundRect.Right - radiusScale + 1, innerRoundRect.Y);
// 右上角
arcRectScale.X = innerRoundRect.Right - RScale;
g.DrawArc(pn, arcRectScale, 270, 90);
g.DrawLine(pn, innerRoundRect.Right, innerRoundRect.Y + radiusScale, innerRoundRect.Right, innerRoundRect.Bottom - radiusScale + 1);
// 右下角
arcRectScale.Y = innerRoundRect.Bottom - RScale;
g.DrawArc(pn, arcRectScale, 0, 90);
g.DrawLine(pn, innerRoundRect.Right - radiusScale + 1, innerRoundRect.Bottom, innerRoundRect.Left + radiusScale, innerRoundRect.Bottom);
// 左下角
arcRectScale.X = innerRoundRect.Left;
g.DrawArc(pn, arcRectScale, 90, 90);
g.DrawLine(pn, innerRoundRect.Left, innerRoundRect.Bottom - radiusScale + 1, innerRoundRect.Left, innerRoundRect.Y + radiusScale);
#endregion

去掉外层圆角矩形的直线,效果如下:

直接计算比例的问题在于,由于矩形长宽大小的不同,计算出来内部(或外部)矩形的缩小或增大的量会不同,原则上,应该是长宽方向上缩小固定的量(类似边框在长宽方向时,边框的大小都是一样的)。因此,最好取其中一个值。

缩小或增大的矩形的圆角半径是否应该对应缩放?这是一直没有很好处理的问题,如果缩小放大的变化不大,则没有太大区别,如果比较大,圆角半径最好保持不变(上例代码为圆角半径也跟着缩放的例子)

通过Inflate()方法缩放矩形

Inflate()可分为实例方法和静态方法,它是专门用于缩放矩形的长宽指定的量的方法,而不是长宽不对等的比例计算。

推荐使用它加上圆角半径不变的方式,计算内层或外层圆角矩形。

Inflate的使用代码如下,其他不变的代码部分不再列出。

var inflateRect = Rectangle.Inflate(roundRect, -8, -8);
// inflateRect.Inflate(-8, -8); // 实例方法,长宽缩小或放大指定的量,改变的实例本身

// others
相关文章
|
9月前
|
C#
C# GDI+绘图(四)实现网格绘制,并填充相应的表格内容
C# GDI+绘图(四)实现网格绘制,并填充相应的表格内容
|
9月前
|
C#
C# GDI+绘图(三)GDI+实现QQ截图类似功能
C# GDI+绘图(三)GDI+实现QQ截图类似功能
|
9月前
|
C#
C# GDI+绘图(二)进阶---Pen/Brush以及坐标轴平移和旋转等
上一篇C# GDI+绘图(一)GDI+介绍及基础,我们介绍了,GDI+的基础,这篇我们对其进阶内容进行学习,分别为Pen/Brush以及坐标轴操作
|
9月前
|
C# 图形学
C# GDI+绘图(一)GDI+介绍及基础
最近,项目中,有一块比较发杂的网格,并在网格上绘有各种颜色和文本,在Dev库中并未找到能实现这种功能的现有或可以二次开发的控件,因此,涉及到GDI+绘图这块陌生的领域。下面即时我在本次学习过程中的笔记,本次内容一共分为4篇,分别都有各自的代码或工程文件提供,有需要的朋友可以下载。
|
C# 图形学 Windows
C# GDI+编程之Graphics类
GDI+是GDI的后继者,它是.NET Framework为操作图形提供的应用程序编程接口,主要用在窗体上绘制各种图形图像,可以用于绘制各种数据图像、数学仿真等。 Graphics类是GDI+的核心,它提供将对象绘制到显式设备的方法。Graphics类封装了绘制直线、曲线、圆形、图像和文本的方法,是一切GDI+操作的基础类。在绘图之前,必须在指定的窗体上创建一个Graphics对象,才能调用Graphics类的方法画图。
299 0
C# GDI+编程之Graphics类
|
区块链 C# 图形学
c# GDI+ 绘制矩形圆角
引用:http://www.cnblogs.com/jasenkin/archive/2012/08/26/draw_rectangle_round.html 一、前言 本文主要介绍C# GDI+如何绘制矩行的圆角,其中涉及到如何使用位操作来处理组合的技巧。
1418 0