C#中GDI+绘制圆弧及圆角矩形等比缩放的绘制
作者:代码迷途 发布时间:2022-06-14 21:15:05
理解圆弧绘制
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
来源:https://juejin.cn/post/7136952741041012750


猜你喜欢
- 概述对于多线程程序来说,生产者和消费者模型是非常经典的模型。更加准确的说,应该叫“生产者-消费者-仓库模型”。离开了仓库,生产者、消费者就缺
- 本文实例为大家分享了ActionBar下拉式导航的实现代码,供大家参考,具体内容如下利用Actionbar同样可以很轻松的实现下拉式的导航方
- 文件写入为提供相对较高性能的文件读写操作,这里果断选择了 NIO 对文件的操作,因为业务背景需要数据的安全落盘。这里主要采用 ByteBuf
- 一、编译环境spring5.0.x源码gradle4.9jdk1.8_151IntelliJ IDEA 2020.1二、安装gradle1、
- 目录Profile用法resourcesfilters多环境配置解决方案Profile用法我们在application.yml中为jdbc.
- 前言最近在用 MVP + RxJava + Retrofit 写项目,觉得相对于其他的开发框架,这的确是给我们带来了很多方便,但是在网上搜寻
- 简介Spring Security 是为了基于Spring的应用程序提供的声明式安全保护的安全性框架。Spring Security 提供了
- 一.介绍观察者模式(Observer Pattern)属于行为型模式。定义了对象之间的一对多依赖,让多个观察者同时监听某一个主题对象,类似于
- 编程语言的流行程度、发展前景、就业市场这些一直都是程序员们非常关注的话题,需求排名是程序员们关注学习的风向标,毕竟是市场经济,学以致用,如果
- 1.打开官网稍微学习一下,了解一下spring cloud是个什么东西,大概有哪些组件等https://spring.io/projects
- 对象重复是指对象里面的变量的值都相等,并不定是地址。list集合存储的类型是基础类型还比较好办,直接把list集合转换成set集合就会自动去
- 一、@Value读取application.properties配置文件中的值application.properties配置文件fileN
- 用户退出应用前给出一个提示是很有必要的,因为可能是用户并不真的想退出,而只是一不小心按下了返回键,大部分应用的做法是在应用退出去前给出一个D
- 这篇文章主要介绍了配置springboot项目使用外部tomcat过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作
- 本文实例为大家分享了Unity3D实现物体旋转缩放移动的具体代码,供大家参考,具体内容如下由于项目运行在安卓上,运用到了插件,比较麻烦。你们
- 前言最近看了一下 Android 上的图表控件,去年做过一款应用也已上架了,也用到了图表控件,但是只是按照官方 demo 集成了,并没有过多
- 1.前言初始化就是给变量一个初始值。 初始化的目的是为了让变量有值,防止使用时出现异常。在构造函数中,有一项重要功能就是对成员变量进行初始化
- 1.C++中的时间:(1) time_t其实是一个64位的long int类型(2) time函数:函数简介:函数名: time
- 一.组合widget实现1.android和flutter自定义控件对比Android中,一般会继承View或已经存在的某个控件,然后覆盖d
- 前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分。它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home