[C#/Wiskunde] Het vinden van de stralen van een ellips

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • JaWSnl
  • Registratie: Maart 2007
  • Laatst online: 16-05 16:56
Wat mijn doel is:
Ik heb een ellips in mijn programma getekend. Als ik op de ellips klik, wil ik dat hij de muis volgt en zijn verhoudingen behoudt.

Hoe ik dat wil doen:
Ik heb het al zo ver dat ik een cirkel kan vergroten en verkleinen terwijl hij mijn muis volgt. Hiervoor pak ik simpelweg de pythagoras van de xy-coordinaat van de muis ten opzichte van de xy-coordinaat van het midden van de cirkel. Dit dus:
C#:
1
2
newRadius.X = newRadius.Y = 
Math.Sqrt(Math.Pow(mousePos.X - ellipse.CenterX, 2) + Math.Pow(mousePos.Y - ellipse.CenterY, 2));


Maar: dit werkt alleen bij een perfect ronde ellips.

In het volgende plaatje zie je 2 ellipsen, een grote en zijn verkleinde versie. De variabelen die je hiervan weet zijn eigenlijk alle behalve X1 en Y1, oftewel de kortste straal en de langste straal in de ellips.
De grote versie is aan het begin van de mouse-drag (M is de muis), de kleine versie is na de mouse-drag. Het blauwe gedeelte is de verandering (oftewel de delta).

Afbeeldingslocatie: http://i45.tinypic.com/11qmskw.png

Hoe kom ik nu, met alle waarden dit ik weet, aan de waarden van X1 en Y1? Het doel is dus dat hoe je de muis ook beweegt, de verhouding van de ellipse altijd hetzelfde blijft en de muis op de rand van de ellips blijft.

Ik heb al geprobeerd om de verhoudingen nog even te berekenen NA dat ik er via bovenstaande code een perfecte cirkel van heb gemaakt, doordat ik de verhoudingen weet van X0 en X1. Lukt (mij) alleen niet. Zou bijvoorbeeld de verhouding tussen R0 en R1 even groot moeten zijn als de verhouding tussen Y0 en Y1? (oftewel: als R1 80% zo groot is als R0, is Y1 dan ook 80% zo groot als Y0)

Ik zit er nu al de hele dag op te puzzelen maar blijkbaar is mijn wiskunde redelijk ver weggezakt.

There are only 10 types of people in the world: those who understand binary and those who don't.


Acties:
  • 0 Henk 'm!

  • atze
  • Registratie: Mei 2003
  • Laatst online: 09-03-2023
Ik zou de parameter vergelijking gebruiken.

Wikipedia: Ellips (wiskunde)

Je weet de hoeken (t in het wikipedia geval). x(t) en y(t) weet je ook en je weet de verhouding tussen a en b.
  1. Dus je berekend eerst de hoek met in jou geval x0. (bij wikipedia is dit a)
  2. Dan gebruik je de hoek en x(t) om een uitdrukking voor a te krijgen
  3. Het zelfde doe je voor b
  4. Je weet de verhouding tussen a en b dus kun je ze vast leggen

Acties:
  • 0 Henk 'm!

Anoniem: 303530

begrijp is het goed dat eclips 1 dezelfde verhoudingen heeft als eclips 2? anders gaan het nevernooit werken

zoja, kan je dan niet gewoon de delta-X uitrekenen aan de hand van de eerste eclips en schalen?

code:
1
2
3
x-scale = breedte / hoogte;
newRadius.X * x-scale = newRadius.Y = 
Math.Sqrt(Math.Pow(mousePos.X - ellipse.CenterX, 2) + Math.Pow(mousePos.Y - ellipse.CenterY, 2));


niet dat ik zo goed ben ik C... (lees: helemaal niet)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16-05 15:50

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je voorbeeld is wat onhandig. Moet je per se op de rand klikken? Mag je alleen draggen in het verlengde van het middelpunt van de cirkel? Mijn vermoeden is dat de antwoorden op deze vragen beide nee zijn, maar het is aan je uitleg niet duidelijk wat er dan moet gebeuren in die gevallen. Moet de ellips ook draaien bijvoorbeeld? Of wil je simpelweg de ellips zo schalen dat de muis altijd op de rand ligt, zonder de ellips te draaien?

Op zich is dat vrij simpel voor elkaar te krijgen. Je maakt het jezelf moeilijker door in image space te werken, maar het voorbeeld met een cirkel heb je al werkend. Het geval van de ellips is precies hetzelfde, alleen moet je even compenseren in het verschil in verhouding, door te werken in een ruimte waarin de verhouding x:y altijd 1 is. Als je weet dat y=2x, dan deel je het y-coordinaat van de muis gewoon door 2 (relatief aan het middelpunt van de cirkel), bereken je de grootte van de cirkel, en vervolgens vermenigvuldig je de straal van de cirkel voor de y-as weer met 2 om de juiste ellips te krijgen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Testje, afgeleid uit de Middelpuntsvergelijking:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Windows.Forms;
using System.Drawing;

static class Program
{
    public class FormEllipse : Form
    {
        Point eCenter = new Point(100, 100);
        PointF radius = new Point(100, 200);
        float ratio = 2F;

        public FormEllipse()
        {
            this.MouseMove += (sender, e) =>
            {
                radius.X = (float)Math.Sqrt(Math.Pow(e.X - eCenter.X, 2) +
                    Math.Pow(e.Y - eCenter.Y, 2) / Math.Pow(ratio, 2));
                radius.Y = ratio * radius.X;
                Invalidate();
            };
            this.Paint += (sender, e) =>
            {
                e.Graphics.DrawEllipse(Pens.Black, eCenter.X - radius.X, 
                    eCenter.Y - radius.Y, 2 * radius.X, 2 * radius.Y);
            };
        }
    }

    static void Main()
    {
        Application.Run(new FormEllipse());
    }
}

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • JaWSnl
  • Registratie: Maart 2007
  • Laatst online: 16-05 16:56
.oisyn schreef op dinsdag 05 januari 2010 @ 17:48:
Je voorbeeld is wat onhandig. Moet je per se op de rand klikken? Mag je alleen draggen in het verlengde van het middelpunt van de cirkel? Mijn vermoeden is dat de antwoorden op deze vragen beide nee zijn, maar het is aan je uitleg niet duidelijk wat er dan moet gebeuren in die gevallen. Moet de ellips ook draaien bijvoorbeeld? Of wil je simpelweg de ellips zo schalen dat de muis altijd op de rand ligt, zonder de ellips te draaien?
1. Je moet per se op de rand klikken.
2. Tussen mouse-down en mouse-up moet de muis zich altijd op de rand van de ellipse bevinden.
3. De ellips kan tijdens deze bewerking niet draaien.

Draaien is op dit moment nog geen deel van mijn taak, maar een ellips kan inderdaad later gewoon gedraaid zijn, wat dat voor problemen zal geven hoop ik dan weer op te lossen ;)

Dus dit is later ook mogelijk, en ook dan moet de verhouding en draaiing gelijk blijven:
Afbeeldingslocatie: http://i48.tinypic.com/28we1p2.png

Update: het gaat nu al beter. Ik heb de ratio toegevoegd (of eigenlijk verbeterd) en hij doet het bijna zoals zou moeten. Alleen nu hoe groter het verschil in verhouding tussen kleine-as en grote-as, hoe meer de ellips verschiet bij het aanklikken van de ellips. Vaag, snap ik, ik ga er nog eens goed naar kijken ;)

Update: Wat er dus fout gaat is dat de muis een cirkelvorm volgt ipv een ellipsevorm. Als ik dus op de rand klik waar y=0 (rechter- en linker-uiterste), dan verschiet hij niet. Als ik klik waar x=0 (onder- en boven-uiterste) dan wordt de ellipse ineens veel groter, door de verhouding waar ik mee vermenigvuldig. Ik heb nu dit:

C#:
1
2
3
4
5
6
7
8
if (editCircle.RadiusX != 0 && editCircle.RadiusY != 0)
    ratio = editCircle.RadiusY / editCircle.RadiusX;
                    
tempRadius.X = Math.Sqrt(Math.Pow(tMousePos.X - editCircle.CenterX, 2) + Math.Pow(tMousePos.Y - editCircle.CenterY, 2));
tempRadius.Y = tempRadius.X;
                    
editCircle.RadiusX = tempRadius.X;                    
editCircle.RadiusY = tempRadius.Y * ratio;


Maar dit gaat dus niet goed. Waar zit de flaw in mn code?

[ Voor 35% gewijzigd door JaWSnl op 05-01-2010 19:34 ]

There are only 10 types of people in the world: those who understand binary and those who don't.


Acties:
  • 0 Henk 'm!

  • JaWSnl
  • Registratie: Maart 2007
  • Laatst online: 16-05 16:56
Eigenlijk moet ik gewoon elke keer dat ik de muis beweeg, een nieuwe ronde ellips "tekenen" (mouse-path) die intersect met de ellips op de plaats waar ik de muis op dat moment houdt... hij moet een perfecte cirkel dus tekenen die niet alleen verschilt in y-as, maar ook in x-as gok ik... we gaan weer even puzzelen.

There are only 10 types of people in the world: those who understand binary and those who don't.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
JaWSnl schreef op dinsdag 05 januari 2010 @ 18:47:
Maar dit gaat dus niet goed. Waar zit de flaw in mn code?
De formule voor tempRadius.X klopt niet, boven jouw post staat er een die iets langer is.. Opnieuw afleiden dus.. ;)

Maar als je later toch wel wil gaan roteren enzo, is een aanpak met transform's/matrices misschien handiger. Ik neem aan dat je op die manier toch al de rotaties wil doen, of zie ik een andere manier over het hoofd?

Ik heb voor de grap zelf wat zitten testen net, hierbij (spoiler):
C#:
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    public static Matrix Inverted(this Matrix m)
    {
        var result = m.Clone();
        result.Invert();
        return result;
    }
    public static PointF TransformPoint(this Matrix m, PointF p)
    {
        var t = new[] { p };
        m.TransformPoints(t);
        return t[0];
    }
    public class FormEllipse : Form
    {
        Matrix Transform = new Matrix();

        public FormEllipse()
        {
            Transform.Scale(1, 2, MatrixOrder.Append);
            Transform.Rotate(60, MatrixOrder.Append);
            Transform.Translate(100, 100, MatrixOrder.Append);
            var DeTransform = Transform.Inverted();
            var pen = new Pen(Color.Black, 4);
            pen.Transform = DeTransform; //undo line width scaling

            this.MouseMove += (sender, e) =>
            {
                var p = DeTransform.TransformPoint(new PointF(e.X, e.Y));
                var r = (float)Math.Sqrt(p.X * p.X + p.Y * p.Y);
                Transform.Scale(r, r, MatrixOrder.Prepend);
                DeTransform = Transform.Inverted();
                pen.Transform = DeTransform;
                Invalidate();
            };
            this.Paint += (sender, e) =>
            {
                var g = e.Graphics;
                g.Transform = Transform;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.DrawEllipse(pen, -1, -1, 2, 2);
            };
        }
    }

Om afrondingsverschillen te voorkomen (bij floats) kan ik me trouwens voorstellen dat je de originele transformatie wil opslaan. Ik vraag me verder af waarom Matrix zo onhandig is om mee te werken, waardoor ik 2 extention methods heb toegevoegd; ik zie dus wellicht iets over het hoofd. ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16-05 15:50

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dit is dus precies wat ik uitlegde.

Overigens is met rotatie wel compleet anders. De schaal en rotatie hou je simpelweg bij door de afstand te pakken tot de muiscursor en die te delen door de afstand van het oorspronkelijke klikpunt. De rotatie is de hoek tussen de lijn van middelpunt tot originele klikpunt en de lijn van het middelpunt en de huidige cursorpositie. Op die manier blijft het punt waar je klikt altijd onder de muiscursor, en schaalt/draait alles mee terwijl je 'm beweegt. Zoals het rotozoomen van foto's op de iPhone met twee vingers.

.edit: oh wacht volgens mij begrijp ik je verkeerd, het is niet de bedoeling dat je zelf de ellips kan draaien?

[ Voor 56% gewijzigd door .oisyn op 06-01-2010 00:21 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • JaWSnl
  • Registratie: Maart 2007
  • Laatst online: 16-05 16:56
pedorus schreef op dinsdag 05 januari 2010 @ 22:55:
[...]

De formule voor tempRadius.X klopt niet, boven jouw post staat er een die iets langer is.. Opnieuw afleiden dus.. ;)
Ik zie het nu pas goed inderdaad >< stom van me, nu doet hij het. Morgen ga ik nog even de tijd nemen om te begrijpen wat ik nu precies doe, nu eerst ff slapen. Op de rest reageer ik morgen nog even :)

There are only 10 types of people in the world: those who understand binary and those who don't.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
.oisyn schreef op woensdag 06 januari 2010 @ 00:14:
Dit is dus precies wat ik uitlegde.
Klopt, in weze heb ik precies dat gecodeerd:
.oisyn schreef op dinsdag 05 januari 2010 @ 17:48:
Als je weet dat y=2x, dan deel je het y-coordinaat van de muis gewoon door 2 (relatief aan het middelpunt van de cirkel), bereken je de grootte van de cirkel, en vervolgens vermenigvuldig je de straal van de cirkel voor de y-as weer met 2 om de juiste ellips te krijgen.
Enkel dat was zo'n wiskunde A verhaal, dat ik toch zelf maar even de formules erbij heb gepakt. ;)
Overigens is met rotatie wel compleet anders. De schaal en rotatie hou je simpelweg bij door de afstand te pakken tot de muiscursor en die te delen door de afstand van het oorspronkelijke klikpunt. De rotatie is de hoek tussen de lijn van middelpunt tot originele klikpunt en de lijn van het middelpunt en de huidige cursorpositie. Op die manier blijft het punt waar je klikt altijd onder de muiscursor, en schaalt/draait alles mee terwijl je 'm beweegt. Zoals het rotozoomen van foto's op de iPhone met twee vingers.
Lijkt me toch een gekke combinatie om draaien en schalen tegelijkertijd te doen. Kan op zich wel natuurlijk, maar ik ken geen programma waar dit tegelijkertijd zo gebeurd.. Even snel getest:
C#:
33
34
35
36
37
38
39
40
            this.MouseMove += (sender, e) =>            
            {
                Transform.Reset();
                Transform.Scale(2, 1, MatrixOrder.Append);
                Transform.Rotate((float)(Math.Atan2(e.Y-100, e.X-100) / Math.PI * 180),
                    MatrixOrder.Append);
                Transform.Translate(100, 100, MatrixOrder.Append);
                DeTransform = Transform.Inverted();

Wat handiger is hangt van je situatie af. Het geeft wel een leuk effect als je 'm ronddraait.. :)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 16-05 15:50

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je pakt daar de hoek tussen de muiscursor en de vector (1, 0), de ellips zal dan altijd zo draaien dat de cursor zich altijd op de lokale x-as van de ellips bevindt. Ik bedoelde de hoek te nemen tussen het originele klikpunt en het huidige punt, en daarmee te draaien. Op die manier kun je dus de ellips "beetpakken" en transformeren.

Als m0 het oude klikpunt was, en m1 het nieuwe, en c het centrum van de cirkel, dan:
v0 = m0-c
l0 = ||v0||
v1 = m1-c
l1 = ||v1||
scale = l1 / l0
rotate = acos(v0∙v1 / l0 / l1)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1