简体   繁体   English

如何用颜色渐变填充椭圆形的圆形扇区?

[英]How can I fill the circular sector of an elliptic shape with a color gradient?

What I want to do is to create this rotating cone visual effect.我想要做的是创建这个旋转的圆锥体视觉效果。
I had previously used DirectX for that.我以前为此使用过 DirectX。

锥体

What i have tried so far:到目前为止我尝试了什么:

Even if I'm changing the thickness to 50 or more, the Arc is still not filled.即使我将厚度更改为50或更多,弧仍未填充。

public partial class Form1 : Form
{
    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        var g = e.Graphics;
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

        var center = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2);
        var innerR = 30;
        var thickness = 20;
        var startAngle = 0;
        var arcLength = 360;
        var outerR = innerR + thickness;
        var outerRect = new Rectangle
                        (center.X - outerR, center.Y - outerR, 2 * outerR, 2 * outerR);
        var innerRect = new Rectangle
                        (center.X - innerR, center.Y - innerR, 2 * innerR, 2 * innerR);

        using (var p = new GraphicsPath())
        {
            p.AddArc(outerRect, startAngle, arcLength);
            p.AddArc(innerRect, startAngle + arcLength, -arcLength);
            p.CloseFigure();
            e.Graphics.FillPath(Brushes.Green, p);
            e.Graphics.DrawPath(Pens.Green, p);
        }
    }
}

I want to be able to fill the arc even when the thickness is 20 or less.即使厚度为 20 或更小,我也希望能够填充圆弧。
Or when the value of the innerR radius changes.或者当innerR半径的值发生变化时。

The goal is to be able to fill the arc in any case.目标是在任何情况下都能够填充弧线。

弧

Here's one method of drawing that cone.这是绘制该圆锥体的一种方法。
It looks like a Radar sweep, so you may want to define the sweep angle and the rotation speed (how much the current rotation angle is increased based on the Timer's interval).它看起来像雷达扫描,因此您可能需要定义扫描角度和旋转速度(当前旋转角度根据定时器的间隔增加多少)。
Using a standard System.Windows.Forms.Timer to invalidate the Canvas that contains the Image you're showing here.使用标准 System.Windows.Forms.Timer 使包含您在此处显示的图像的 Canvas 无效。

The Radar contour (the external perimeter) is centered on the canvas and drawn in relation to the thickness specified (so it's always sized as the canvas bounds).雷达等高线(外围)以 canvas 为中心,并根据指定的厚度绘制(因此它的大小始终为 canvas 边界)。 It doesn't necessarily be a perfect circle, it can be elliptical (as in the image here)它不一定是一个完美的圆,它可以是椭圆形的(如图所示)

The Cone section is drawn adding an Arc to a GraphicsPath and is closed drawing two lines, from the center point of the outer GraphicsPath to the starting and ending points of the Arc (I think this is a simple method to generate a curved conic figure, it can be used in different situations and lets you generate different shapes almost without calculations, see the code about this) Cone部分是通过向 GraphicsPath 添加 Arc 绘制的,并关闭绘制两条线,从外部 GraphicsPath 的中心点到 Arc 的起点和终点(我认为这是生成曲线圆锥图形的简单方法,它可以在不同的情况下使用,让你几乎不需要计算就可以生成不同的形状,参见代码)

It's filled with a LinearGradientBrush , the section near the center has less transparency than the section near the border;它填充了LinearGradientBrush ,靠近中心的部分比靠近边界的部分透明度低; adjust as required根据需要调整

Each time the rotation angle reaches 360° , it's reset to 0 .每次旋转角度达到360°时,它都会重置为0
This is delegated to the Timer's Tick event handler这是委托给定时器的Tick事件处理程序

=> Built with.Net 7, but if you need to adapt it to.Net Framework, the only things to change are the syntax of the using blocks, remove the null-forgiving operator from here: canvas..ClientRectangle and nullable reference types (eg, change object? to just object ) => 使用.Net 7 构建,但如果您需要将其适配到.Net Framework,唯一需要更改的是using块的语法,从此处删除null-forgiving 运算符: canvas..ClientRectangle和可为空的引用类型(例如,将object?更改为object

public partial class SomeForm : Form {
    public SomeForm() {
        InitializeComponent();
        radarTimer.Interval = 100;
        radarTimer.Tick += RadarTimer_Tick;
    }

    float coneSweepAngle = 36.0f;
    float coneRotationAngle = .0f;
    float radarSpeed = 1.8f;
    float radarThickness = 5.0f;
    System.Windows.Forms.Timer radarTimer = new System.Windows.Forms.Timer();

    private void RadarTimer_Tick(object? sender, EventArgs e) {
        coneRotationAngle += radarSpeed;
        coneRotationAngle %= 360.0f;
        canvas.Invalidate();
    }

    private void canvas_Paint(object sender, PaintEventArgs e) {
        var center = new PointF(canvas.Width / 2.0f, canvas.Height / 2.0f);
        RectangleF outerRect = canvas!.ClientRectangle;
        outerRect.Inflate(-(radarThickness / 2.0f), -(radarThickness / 2.0f));

        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

        using var pathOuter = new GraphicsPath();
        using var pathInner = new GraphicsPath();
        pathOuter.AddEllipse(outerRect);

        pathInner.StartFigure();
        pathInner.AddArc(outerRect, coneRotationAngle, coneSweepAngle);
        var arcPoints = pathInner.PathPoints;
        PointF first = arcPoints[0];
        PointF last = arcPoints[arcPoints.Length - 1];
        pathInner.AddLines(new[] { center, last, center, first });
        pathInner.CloseFigure();

        using var outerPen = new Pen(Color.FromArgb(100, Color.Red), radarThickness);
        using var innerBrush = new LinearGradientBrush(
            center, first, Color.FromArgb(200, Color.Orange), Color.FromArgb(20, Color.Orange));

        e.Graphics.FillPath(innerBrush, pathInner);
        e.Graphics.DrawPath(outerPen, pathOuter);
    }
}

This is how it works:它是这样工作的:

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM