在C#中创建类似Google地图的锥形渐变。

huangapple go评论73阅读模式
英文:

Create cone gradient like in google maps in c#

问题

以下是已经翻译好的内容:

我希望我的最终结果是这样的

[![输入图像描述][1]][1]


我的三个要求是

 1. 控制颜色
 2. 控制锥体的角度
 3. 控制角度的“宽度”(在0-360之间)

我的代码如下

     internal static Bitmap Generate()
            {
                int width = 160;
                int height = 160;
                var color1 = CreateRandomShare(Color.AliceBlue);
                var color2 = CreateRandomShare(Color.Navy);
                var bitmap = GenerateGradient(color1, color2, width, height, LinearGradientMode.BackwardDiagonal);
                bitmap.Save("test.bmp", ImageFormat.Bmp);
    
                return bitmap;
    
            }
    
     private static Color CreateRandomShare(Color color)
            {
                const int range = 1000;
                const int variance = 700;
                var random = new Random(DateTime.Now.Millisecond);
                int factor = random.Next(range - variance, range + variance + 1);
                int r = color.R + factor / range;
                int g = color.G + factor / range;
                int b = color.B + factor / range;
    
                return Color.FromArgb(255, Math.Min(r, 255), Math.Min(g, 255), Math.Min(b, 255));
    
            }
    
            private static Bitmap GenerateGradient(Color color1, Color color2, int width, int height, LinearGradientMode mode)
            {
                Bitmap bmp = new Bitmap(width, height);
                Graphics g = Graphics.FromImage(bmp);
                var brush = new LinearGradientBrush(new Rectangle(0, 0, width, height), color1, color2, mode);
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = SmoothingMode.AntiAlias;
                PointF[] points =
                {
                    new (50, 50),
                    new (100, 25),
                    new (200, 5),
                    new (250, 5),
                    new (300, 100),
                    new (350, 200),
                    new (250, 250),
                };
    
    
                g.FillPolygon(brush, points);
                return bmp;
            }

和我的最终结果

[![输入图像描述][2]][2]

有点接近

我的问题是我不知道如何满足要求(2)和(3)


  [1]: https://i.stack.imgur.com/aWaIs.jpg
  [2]: https://i.stack.imgur.com/oYbQc.png
英文:

I want my end result to be something like this

在C#中创建类似Google地图的锥形渐变。

and my 3 requirements are

  1. Control the color
  2. Control the angle of the cone
  3. Control the degree how "wide" the angle is(between 0-360)

My code is as follows

 internal static Bitmap Generate()
        {
            int width = 160;
            int height = 160;
            var color1 = CreateRandomShare(Color.AliceBlue);
            var color2 = CreateRandomShare(Color.Navy);
            var bitmap = GenerateGradient(color1, color2, width, height, LinearGradientMode.BackwardDiagonal);
            bitmap.Save("test.bmp", ImageFormat.Bmp);

            return bitmap;

        }

 private static Color CreateRandomShare(Color color)
        {
            const int range = 1000;
            const int variance = 700;
            var random = new Random(DateTime.Now.Millisecond);
            int factor = random.Next(range - variance, range + variance + 1);
            int r = color.R + factor / range;
            int g = color.G + factor / range;
            int b = color.B + factor / range;

            return Color.FromArgb(255, Math.Min(r, 255), Math.Min(g, 255), Math.Min(b, 255));

        }

        private static Bitmap GenerateGradient(Color color1, Color color2, int width, int height, LinearGradientMode mode)
        {
            Bitmap bmp = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(bmp);
            var brush = new LinearGradientBrush(new Rectangle(0, 0, width, height), color1, color2, mode);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            PointF[] points =
            {
                new (50, 50),
                new (100, 25),
                new (200, 5),
                new (250, 5),
                new (300, 100),
                new (350, 200),
                new (250, 250),
            };


            g.FillPolygon(brush, points);
            return bmp;
        }

and my final result

在C#中创建类似Google地图的锥形渐变。

which is kind of close

my problem is that I do not know how to meet requirements (2) and (3)

答案1

得分: 1

以下是您要翻译的内容:

  1. Draw a sector, i.e. a shape looking like a piece of a pizza.
    绘制扇形,即类似披萨片的形状。

  2. Draw a radial gradient.
    绘制径向渐变。

Let's create a method with this signature where the angles are measured in degrees (360 degrees = one full turn):

private static void DrawSector(Graphics g, Rectangle rect,
    float startAngle, float sweepAngle, Color color)

让我们创建一个具有此签名的方法,其中角度以度为单位(360度=一圈):

private static void DrawSector(Graphics g, Rectangle rect,
    float startAngle, float sweepAngle, Color color)

Let's also calculate these angles in radians as input for trigonometric functions as well as a few other values we will need later:

float startAngleRadians = startAngle * MathF.PI / 180f;
float endAngleRadians = (startAngle + sweepAngle) * MathF.PI / 180f;

float radius = 0.5f * rect.Width;
float centerX = rect.X + radius;
float centerY = rect.Y + radius;

让我们还要将这些角度计算为弧度,以供三角函数使用,并计算稍后需要的一些其他值:

float startAngleRadians = startAngle * MathF.PI / 180f;
float endAngleRadians = (startAngle + sweepAngle) * MathF.PI / 180f;

float radius = 0.5f * rect.Width;
float centerX = rect.X + radius;
float centerY = rect.Y + radius;

To draw a sector, we can construct a path consisting of:

  1. a radial line starting at the center and going towards the start of an arc
  2. an arc segment
  3. a line starting at the end of the arc going back to the center

The same path will be used to draw the shape and to define a PathGradientBrush.

var center = new PointF(centerX, centerY);
var startOfArc = new PointF(
    centerX + radius * MathF.Cos(startAngleRadians),
    centerY + radius * MathF.Sin(startAngleRadians));
var endOfArc = new PointF(
    centerX + radius * MathF.Cos(endAngleRadians),
    centerY + radius * MathF.Sin(endAngleRadians));

using var path = new GraphicsPath();
path.AddLine(center, startOfArc);
path.AddArc(rect, startAngle, sweepAngle);
path.AddLine(endOfArc, center);

要绘制扇形,我们可以构建一个路径,其中包括:

  1. 从中心开始并朝着弧的起点的径向线
  2. 一个弧段
  3. 从弧的末端开始返回到中心的线

同一路径将用于绘制形状并定义PathGradientBrush

var center = new PointF(centerX, centerY);
var startOfArc = new PointF(
    centerX + radius * MathF.Cos(startAngleRadians),
    centerY + radius * MathF.Sin(startAngleRadians));
var endOfArc = new PointF(
    centerX + radius * MathF.Cos(endAngleRadians),
    centerY + radius * MathF.Sin(endAngleRadians));

using var path = new GraphicsPath();
path.AddLine(center, startOfArc);
path.AddArc(rect, startAngle, sweepAngle);
path.AddLine(endOfArc, center);

Now, let's define a gradient brush. We are using the same color as start color and end color, but we make the end color transparent, so that the sector will fade out gradually revealing more and more of the background.

Then all we have to do, is to draw the path with this gradient brush:

using var brush = new PathGradientBrush(path) {
    CenterColor = color,
    CenterPoint = center,
    SurroundColors = new[] { Color.FromArgb(0, color) }
};
g.FillPath(brush, path);

现在,让我们定义一个渐变刷。我们使用与起始颜色和结束颜色相同的颜色,但我们使结束颜色透明,以便扇形将逐渐淡出,逐渐显露更多的背景。

然后,我们所要做的就是使用这个渐变刷绘制路径:

using var brush = new PathGradientBrush(path) {
    CenterColor = color,
    CenterPoint = center,
    SurroundColors = new[] { Color.FromArgb(0, color) }
};
g.FillPath(brush, path);

For testing, let's call it in an empty WinForms form like this:

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.Clear(Color.Black);
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

    // Create a centered square
    int length = Math.Min(ClientSize.Width, ClientSize.Height) - 6;
    int dx = (ClientSize.Width - length) / 2;
    int dy = (ClientSize.Height - length) / 2;
    var rect = new Rectangle(dx, dy, length, length);

    // Create a sector with a random sweep angle pointing upwards
    float sweepAngle = Random.Shared.NextSingle() * 360;
    float startAngle = -90f - 0.5f * sweepAngle;
    DrawSector(e.Graphics, rect, startAngle, sweepAngle, Color.Blue);
}

为了测试,让我们在一个空的WinForms窗体中调用它,就像这样:

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.Clear(Color.Black);
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

    // Create a centered square
    int length = Math.Min(ClientSize.Width, ClientSize.Height) - 6;
    int dx = (ClientSize.Width - length) / 2;
    int dy = (ClientSize.Height - length) / 2;
    var rect = new Rectangle(dx, dy, length, length);

    // Create a sector with a random sweep angle pointing upwards
    float sweepAngle = Random.Shared.NextSingle() * 360;
    float startAngle = -90f - 0.5f * sweepAngle;
    DrawSector(e.Graphics, rect, startAngle, sweepAngle, Color.Blue);
}

Let's also add a click event handler to redraw the arc with other random settings (make sure it is wired up):

private void Form1_Click(object sender, EventArgs e)
{
    Invalidate();
}

让我们还添加一个点击事件处理程序,以使用其他随机设置重新绘制弧形(确保已连接):

private void Form1_Click(object sender, EventArgs e)
{
    Invalidate();
}

The result looks like this:
在C#中创建类似Google地图的锥形渐变。

Note: `Random.Shared

英文:

There are mainly two tasks we must solve:

  1. Draw a sector, i.e. a shape looking like a piece of a pizza.
  2. Draw a radial gradient.

Let's create a method with this signature where the angles are measured in degrees (360 degrees = one full turn):

private static void DrawSector(Graphics g, Rectangle rect,
    float startAngle, float sweepAngle, Color color)

Let's also calculate these angles in radians as input for trigonometric functions as well as a few other values we will need later:

float startAngleRadians = startAngle * MathF.PI / 180f;
float endAngleRadians = (startAngle + sweepAngle) * MathF.PI / 180f;

float radius = 0.5f * rect.Width;
float centerX = rect.X + radius;
float centerY = rect.Y + radius;

To draw a sector, we can construct a path consisting of:

  1. a radial line starting at the center and going towards the start of an arc
  2. an arc segment
  3. a line starting at the end of the arc going back to the center

The same path will be used to draw the shape and to define a PathGradientBrush.

var center = new PointF(centerX, centerY);
var startOfArc = new PointF(
    centerX + radius * MathF.Cos(startAngleRadians),
    centerY + radius * MathF.Sin(startAngleRadians));
var endOfArc = new PointF(
    centerX + radius * MathF.Cos(endAngleRadians),
    centerY + radius * MathF.Sin(endAngleRadians));

using var path = new GraphicsPath();
path.AddLine(center, startOfArc);
path.AddArc(rect, startAngle, sweepAngle);
path.AddLine(endOfArc, center);

Now, let's define a gradient brush. We are using the same color as start color and end color, but we make the end color transparent, so that the sector will fade out gradually revealing more and more of the background.

Then all we have to do, is to draw the path with this gradient brush:

using var brush = new PathGradientBrush(path) {
    CenterColor = color,
    CenterPoint = center,
    SurroundColors = new[] { Color.FromArgb(0, color) }
};
g.FillPath(brush, path);

For testing, let's call it in an empty WinForms form like this:

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.Clear(Color.Black);
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

    // Create a centered square
    int length = Math.Min(ClientSize.Width, ClientSize.Height) - 6;
    int dx = (ClientSize.Width - length) / 2;
    int dy = (ClientSize.Height - length) / 2;
    var rect = new Rectangle(dx, dy, length, length);

    // Create a sector with a random sweep angle pointing upwards
    float sweepAngle = Random.Shared.NextSingle() * 360;
    float startAngle = -90f - 0.5f * sweepAngle;
    DrawSector(e.Graphics, rect, startAngle, sweepAngle, Color.Blue);
}

Let's also add a click event handler to redraw the arc with other random settings (make sure it is wired up):

private void Form1_Click(object sender, EventArgs e)
{
    Invalidate();
}

The result looks like this:
在C#中创建类似Google地图的锥形渐变。

Note: Random.Shared exists since .NET 6. For older .NET versions, just create a random object yourself.

huangapple
  • 本文由 发表于 2023年6月25日 22:36:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76550917.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定