开发者

how to deform an ellipse in running time

i first sorry about my english,i´ll try to explain want i want to do i need to draw an ellipse with wpf that represents an aura and it´s "deformations" representing problematic zones in it,in short an ellipse that can be deformed in running time in specific points

I'm trying to draw several bezier curves forming an ellipse but开发者_开发问答 it´t very difficult (and i don´t know how) to make points that can be dragged forming convex or hollow zones in that ellipse.

¿i made myselft clear in my spanglish? ¿is there an easy way to do that?

Thanks in advance


I don't know what exactly you are trying to do but I recommend making a high resolution version of the ellipse and keeping track of the deformations yourself. Here is a sample program to get you started.

For this demo the XAML is simple:

<Canvas Name="canvas" Focusable="True" KeyDown="canvas_KeyDown" MouseDown="canvas_MouseDown" MouseMove="canvas_MouseMove" MouseUp="canvas_MouseUp"/>

and a the code-behind:

public partial class EllipseDemo : Window
{
    const int resolution = 1000;
    const double major = 150;
    const double minor = 100;
    const double xOrigin = 200;
    const double yOrigin = 200;
    const double radius = 10;
    const double scale = 0.1;
    const double spread = 10;
    const double magnitude = 10;

    Path path;
    Ellipse controlPoint;
    LineSegment[] segments;
    double[] deformation;
    double[] perturbation;
    int controlPointIndex;

    public EllipseDemo()
    {
        InitializeComponent();

        segments = new LineSegment[resolution];
        deformation = new double[resolution];
        perturbation = new double[resolution];
        for (int i = 0; i < resolution; i++)
        {
            var x = i >= resolution / 2 ? i - resolution : i;
            perturbation[i] = magnitude * Math.Exp(-Math.Pow(scale * x, 2) / spread);
        }
        path = new Path();
        path.Stroke = new SolidColorBrush(Colors.Black);
        path.StrokeThickness = 5;
        CalculateEllipse();
        canvas.Children.Add(path);

        controlPoint = new Ellipse();
        controlPoint.Stroke = new SolidColorBrush(Colors.Red);
        controlPoint.Fill = new SolidColorBrush(Colors.Transparent);
        controlPoint.Width = 2 * radius;
        controlPoint.Height = 2 * radius;
        MoveControlPoint(0);
        canvas.Children.Add(controlPoint);

        canvas.Focus();
    }

    void CalculateEllipse()
    {
        for (int i = 0; i < resolution; i++)
        {
            double angle = 2 * Math.PI * i / resolution;
            double x = xOrigin + Math.Cos(angle) * (major + deformation[i]);
            double y = yOrigin + Math.Sin(angle) * (minor + deformation[i]);
            segments[i] = new LineSegment(new Point(x, y), true);
        }
        var figure = new PathFigure(segments[0].Point, segments, true);
        var figures = new PathFigureCollection();
        figures.Add(figure);
        var geometry = new PathGeometry();
        geometry.Figures = figures;
        path.Data = geometry;
    }

    void MoveControlPoint(int index)
    {
        controlPointIndex = index;
        Canvas.SetLeft(controlPoint, segments[index].Point.X - radius);
        Canvas.SetTop(controlPoint, segments[index].Point.Y - radius);
    }

    bool mouseDown;

    void canvas_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (Mouse.DirectlyOver != controlPoint)
            return;
        mouseDown = true;
        controlPoint.CaptureMouse();
    }

    void canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (!mouseDown)
            return;
        int index = FindNearestIndex(e.GetPosition(canvas));
        MoveControlPoint(index);
    }

    void canvas_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (!mouseDown)
            return;
        controlPoint.ReleaseMouseCapture();
        mouseDown = false;
    }

    private void canvas_KeyDown(object sender, KeyEventArgs e)
    {
        int delta = 0;
        switch (e.Key)
        {
            case Key.Up:
                delta = 1;
                break;
            case Key.Down:
                delta = -1;
                break;
        }
        if (delta == 0)
            return;
        int index = controlPointIndex;
        for (int i = 0; i < resolution; i++)
            deformation[(i + index) % resolution] += delta * perturbation[i];
        CalculateEllipse();
        MoveControlPoint(index);
    }

    int FindNearestIndex(Point point)
    {
        var min = double.PositiveInfinity;
        var index = -1;
        for (int i = 0; i < segments.Length; i++)
        {
            var vector = point - segments[i].Point;
            var distance = vector.LengthSquared;
            if (distance < min)
            {
                index = i;
                min = distance;
            }
        }
        return index;
    }
}

This works mostly with a Path represented by line segments and an Ellipse as a control point. The mouse can move the control point around the ellipse and then the arrow keys add or remove a canned perturbation. Everything is hard coded but if you are OK with the math then it should help you get started.

Here's the program in action:

how to deform an ellipse in running time

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜