如何在重叠时将两个椭圆连接或混合在一起

时间:2014-12-06 05:27:03

标签: gdi+ graphicspath

想知道当它们彼此接触时是否存在混合椭圆的功能。我正在考虑一个GraphicsPath对象,因为它将对象添加到它的路径中。如果有一个术语,我不知道它会是什么,所以搜索到目前为止还没有透露任何内容。感谢您提供一些指导。

目标图片(大致):

Blended Ellipses

1 个答案:

答案 0 :(得分:1)

我不知道你可以做到这一点,但是为了你的特定目标,你可以用这样的东西重新计算路径(使用双重缓冲):

    float px = 0;
    float py = 0;
    float dxy = 0;
    float centerx;
    float centery;
    float mainAngle = 0;

    private List<PointF> myCircle(int points, float radius)
    {
        List<PointF> result = new List<PointF>();


        for (int i = 0; i < points; i++)
        {
            result.Add(new PointF(radius * (float)Math.Cos(2 * Math.PI * (double)i / (points - 1)), radius * (float)Math.Sin(2 * Math.PI * (double)i / (points - 1))));
        }

        return result;
    }

    private List<PointF> myBlendedCircles(int points,float radius)
    {

        List<PointF> result = new List<PointF>();
        float linkcircle = radius / 2f;
        float A = radius + linkcircle;
        float B = dxy / 2f;
        float angle = (float)Math.Acos(B / A);
        float angle2 = ((float)Math.PI/2f - angle);
        // circle 1

        for (int i = 0; i < points; i++)
        {
            result.Add(new PointF(radius * (float)Math.Cos(angle + (2 * Math.PI - 2f*angle) * (double)i / (points - 1)), radius * (float)Math.Sin(angle + (2 * Math.PI - 2f*angle) * (double)i / (points - 1))));
        }

        // link1
        for (int i = 0; i < points; i++)
        {
            result.Add(new PointF(linkcircle * (float)Math.Cos(-(float)Math.PI * 3.0 / 2.0 + angle2 - (2.0 * angle2) * (double)i / (points - 1)) + dxy / 2f, linkcircle * (float)Math.Sin(-(float)Math.PI * 3.0 / 2.0 + angle2 - (2.0 * angle2) * (double)i / (points - 1)) - A * (float)Math.Sin(angle)));
        }
        //circle2
        for (int i = 0; i < points; i++)
        {
            result.Add(new PointF(radius * (float)Math.Cos((float)Math.PI + angle + (2 * Math.PI - 2f * angle) * (double)i / (points - 1)) + dxy, radius * (float)Math.Sin((float)Math.PI + angle + (2 * Math.PI - 2f * angle) * (double)i / (points - 1))));
        }
        //link2
        for (int i = 0; i < points; i++)
        {
            result.Add(new PointF(linkcircle * (float)Math.Cos((float)Math.PI * 3.0 / 2.0 + angle2 - (2.0 * angle2) * (double)i / (points - 1)) + dxy / 2f, linkcircle * (float)Math.Sin((float)Math.PI * 3.0 / 2.0 + angle2 - (2.0 * angle2) * (double)i / (points - 1)) + A * (float)Math.Sin(angle)));
        }
        return result;
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {

        centerx = (float)this.Width / 2f;
        centery = (float)this.Height / 2f;
        GraphicsPath gp1 = new GraphicsPath();

        gp1.AddLines(myCircle(36,40).ToArray());

        e.Graphics.TranslateTransform(centerx, centery);

        e.Graphics.DrawPath(Pens.Black, gp1);

        e.Graphics.TranslateTransform(-centerx, -centery);

        e.Graphics.TranslateTransform(px, py);
        e.Graphics.DrawPath(Pens.Blue, gp1);
        e.Graphics.TranslateTransform(-px, -py);

        if(dxy<40f*2f)
        {
            GraphicsPath gp2 = new GraphicsPath();
            gp2.AddLines(myBlendedCircles(36, 40).ToArray());
            e.Graphics.TranslateTransform(centerx, centery);
            e.Graphics.RotateTransform(mainAngle);
            e.Graphics.DrawPath(new Pen(Color.Red,2f), gp2);
            e.Graphics.RotateTransform(-mainAngle);
            e.Graphics.TranslateTransform(-centerx, -centery);
        }
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        px = e.X;
        py = e.Y;

        dxy = (float)Math.Sqrt((px - centerx) * (px - centerx) + (py - centery) * (py - centery));
        mainAngle = (float)Math.Atan2(py - centery, px - centerx)*180f/(float)Math.PI;
        label1.Text = mainAngle.ToString();
        this.Invalidate();
    }

该函数可以直接返回路径。对于不同半径的圆圈(我没有尝试更复杂的两个椭圆的情况),你可以使用这样的东西:

    private GraphicsPath myBlendedCircles(float radius1, float radius2)
    {
        GraphicsPath result = new GraphicsPath();

        float radiusL = (radius1 + radius2) / 4;
        float pif = (float)Math.PI;
        float l1 = radius1 + radiusL;
        float l2 = radius2 + radiusL;

        //angle calculation: Al'Kashi
        float alpha = (float)Math.Acos((l1 * l1 + dxy * dxy - l2 * l2) / (2f * l1 * dxy));
        float beta = (float)Math.Acos((l2 * l2 + dxy * dxy - l1 * l1) / (2f * l2 * dxy));
        float gamma = (float)Math.Acos((l1 * l1 + l2 * l2 - dxy * dxy) / (2f * l1 * l2));

        // position of link circles
        float lx = l1 * (float)Math.Cos(alpha);
        float ly = l1 * (float)Math.Sin(alpha);

        result.AddArc(-radius1, -radius1, 2 * radius1, 2 * radius1, 180 * alpha / pif, 360 - 2 * alpha * 180 / pif);
        result.AddArc(lx - radiusL, -ly - radiusL, 2 * radiusL, 2 * radiusL, 180-180 * alpha / pif, -180 * gamma / pif);
        result.AddArc(dxy - radius2, -radius2, 2 * radius2, 2 * radius2, -180 + beta * 180 / pif, 360 - 2 * beta * 180 / pif);
        result.AddArc(lx - radiusL, ly - radiusL, 2 * radiusL, 2 * radiusL, 180+180 * (alpha+gamma) / pif, -180 * gamma / pif);

        return result;
    }

它应该与逻辑测试一起使用,如:

    if (dxy < (radius1 + radius2) && (dxy+Math.Min(radius1,radius2))>Math.Max(radius1,radius2))