cómo deformar una elipse en tiempo de ejecución

Primero lamento mi inglés, intentaré explicar lo que quiero hacer. Necesito dibujar una elipse con wpf que represente un aura y sus "deformaciones" que representan zonas problemáticas en ella, en resumen, una elipse que puede ser deformado en tiempo de ejecución en puntos específicos

Estoy intentando dibujar varias curvas Bézier formando una elipse pero no es muy difícil (y no sé cómo) hacer puntos que se puedan arrastrar formando zonas convexas o huecas en esa elipse.

¿Me dejé claro en mi spanglish? ¿Hay alguna forma fácil de hacer eso?

Gracias por adelantado

preguntado el 08 de enero de 11 a las 18:01

1 Respuestas

No sé qué estás tratando de hacer exactamente, pero te recomiendo que hagas una versión de alta resolución de la elipse y que sigas las deformaciones tú mismo. Aquí hay un programa de muestra para comenzar.

Para esta demostración, XAML es simple:

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

y un código subyacente:

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;
    }
}

Esto funciona principalmente con un Path representado por segmentos de línea y un Ellipse como punto de control. El mouse puede mover el punto de control alrededor de la elipse y luego las teclas de flecha agregan o eliminan una perturbación enlatada. Todo está codificado, pero si está bien con las matemáticas, entonces debería ayudarlo a comenzar.

Aquí está el programa en acción:

Demostración de elipse

Respondido el 10 de enero de 11 a las 01:01

Gracias perdón por la demora en la respuesta, lo intentaré, pero creo que esto es lo que necesito. - Indy81

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.