Einzelnen Beitrag anzeigen

Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#17

Re: Benötige Hilfe von einen Mathematiker

  Alt 17. Dez 2008, 08:27
Okay, ich poste dann mal den momentanen Code:
Code:
public partial class Form1 : Form
    {
        float margin = 30; // Abstand Ellipse <> Button
        float distance = 50; // Abstand Button <> Button
        double start_angle = 1.15 * Math.PI; // Startwinkel im Bogenmaß, hier so "links unten"
        double end_angle = 1.75 * Math.PI; // Endwinkel, hier ~ "unten rechts"

        List<RadioButton> buttons;

        public Form1()
        {
            InitializeComponent();

            buttons = new List<RadioButton>();
            buttons.Add(radioButton1);
            button1_Click(null, null);
            button1_Click(null, null);
        }

        private float sqr(float a)
        { return a * a; }

        private float Abstand(PointF p1, PointF p2)
        {
            return (float)Math.Sqrt(sqr(p1.X - p2.X) + sqr(p1.Y - p2.Y));
        }

        private PointF GetPoint(float a, float b, double phi)
        {
            return new PointF((float)(a * Math.Cos(phi)), (float)(b * Math.Sin(phi)));
        }

        private double GetNewPhi(float a, float b, double oldphi, double arc)
        {
            double step = 0.005;

            double result = oldphi;

            PointF old = GetPoint(a, b, oldphi);

            do
            {
                result += step;
            }
            while (Abstand(old, GetPoint(a, b, result)) < arc);

            return result;
        }

        private Point PointToKoord(float a, float b, double phi, float margin)
        {
            PointF Res = GetPoint(a + margin, b + margin, phi);

            Res.Y = -Res.Y; // Y-Achse umkehren

            Res.X += a;
            Res.Y += (pictureBox1.Height - b);

            Res.X += pictureBox1.Left;
            Res.Y += pictureBox1.Top;

            Res.X -= radioButton1.Width / 2;
            Res.Y -= radioButton1.Height / 2;

            return new Point((int)Res.X, (int)Res.Y);
        }

        private void pictureBox1_SizeChanged(object sender, EventArgs e)
        {
            float hratio = (240f / 293) * pictureBox1.Height / pictureBox1.Width;
            float a = pictureBox1.Width / 2f;
            float b = a * hratio;

            double phi = start_angle;

            foreach (RadioButton elem in buttons)
                elem.Visible = false;

            for(int i = 0; i < buttons.Count; i++)
            {
                buttons[i].Visible = true;
                buttons[i].Location = PointToKoord(a, b, phi, margin);

                phi = GetNewPhi(a, b, phi, distance);

                if (phi > end_angle)
                    break;
            }

        }
Wie du siehst, kängt da noch ein kleiner Rattenschwanz an Funktionen dran, damit es etwas einfacher wird.

Mal kurz alles erklärt:

Allgemein
a und b beschreiben die Ellipse. Siehe auch Wikipedia (Die beiden Achsenabschnitte: a ist horizontal, b ist vertikal).

Der Winkel in der Ellipse beschreibt dann einen Punkt. Der Koordinatenursprung hierfür ist der Ellipsenmittelpunkt. Der Winkel fängt nach rechts mit 0 an und ist positiv gegen den Uhrzeigersinn. Er wird im Bpgenmaß gezählt.
D.h. ein Wert von PI entspricht "links" und ein Wert von 1.5 * Pi entspricht "unten".

sqr()
Quadriert das Argument.

Abstand()
Berechnet den Abstand zwischen 2 Punkten mit Pythagoras.

GetPoint()
Rechnet die Koordinaten um.
Die Parameter a und b beschreiben die Ellipse, der Winkel phi beschreibt dann einen Punkt auf der Ellipse. Die Funktion gibt dann den Punkt in kartesischen Koordinatren zurück. (hier zeigt die y-Achse noch nach oben, beim debuggen nicht wundern)

GetNewPhi
Das ist die iterative Berechnung von Phi. Es wird sozusagen solange der Winkel ein Stückchen erhöähtr, bis der gegebene Anstand erreicht (= etwas überschritten) wurde.

GetNewPhi berechnet allerdings der Geschwindigkeit wegen den Abstand mit dem Pythagoras, was aber falsch ist. Korrekt wäre, alle infinitesimalen Abstände zu integrieren. Wenn die Ellipse aber nicht gerade ein Verhältnis von 10:1 hat, ist das eine akzeptable Näherung.
(Näherung wird schlechter, wenn der Abstand größer wird, oder die Ellipse "platter")

PointToKoord
Rechnet die Koordinaten um, machst also aus einem Punkt auf der Ellipse die Position für den Radiobutton.

Zuerst wird die Position ind kartesische Koordinaten umgewandelt, dann muss die Y-Achse umgedreht werdern. (Da bei uns ja Y nach unten größer wird.)
Anschließend muss man noch die Koordinaten (Die ja relativ zum Ellipsenmitelpunkt sind) relativ zum Formular machen.

SizeChanged
Hier werden die Buttons neu arrangiert. a und b müssen berechnet werden (Beschreiben ja die Ellipse die auf dem Bild zu sehen ist)

In jedem Schritt wird dann ein Radiobutton angeordnet, und der Winkel für den nächsten berechnet. Sollte dieser über dem endwinkel liegen, wird abgebrochen

Wieviele Radiobuttons in den Bereich passen, kann man vorher leider nicht genau sagen.

Falls du noch Fragen hast, frag

Grüße,
Julius
  Mit Zitat antworten Zitat