Winkel zwischen 2 Punkten und der X-Achse

Mikescher

Mitglied
Guten Mittag,

ich bin gerade an einem ziemlich verzwickten Problem:
ich möchte den Winkel zwischen 2 Punkten und der X-Achse angeben. Der Winkel soll mit dem Uhrzeigersinn verlaufen.
Hier sind 3 Beispiele was für Winkel die Funktion eigentlich liefern sollte :
bspy.jpg


gelöst habe ich (bisher das so):
Java:
    /**
     * berechnet den Winkel zweier Punkte relativ zur X-Achse im Gradmaß
     *
     * @param otherP Den 2. Punkt der Winkelberechnung
     * @return Der Winkel der 2 Punkte
     */
    public int getAngle(TPos otherP)
    {       
        int dx = otherP.getX() - this.getX();
        int dy = otherP.getY() - this.getY();
        int adx = Math.abs(dx);
        int ady = Math.abs(dy);
        
        if (dy == 0 && dx == 0)
        {
            return 0;
        }
        else if (dy == 0 && dx > 0)
        {
            return 0;      
        }
        else if (dy == 0 && dx < 0)
        {
            return 180;
        }
        else if (dy > 0 && dx == 0)
        {
            return 270;
        }
        else if (dy < 0 && dx == 0)
        {
            return 90;
        }
        
        double rwinkel = Math.atan(ady /adx);  
        double dWinkel = 0;
            
        if (dx>0 && dy>0)  // 1. Quartal Winkkel von 270° - 359°
        {
            dWinkel = 360 - Math.toDegrees(rwinkel);
        }
        else if (dx<0 && dy>0)  // 2. Quartal Winkkel von 180° - 269°
        {
            dWinkel = 180 + Math.toDegrees(rwinkel);
        }
        else if (dx>0 && dy<0)  // 3. Quartal Winkkel von 90° - 179°
        {
            dWinkel = 180 - Math.toDegrees(rwinkel);
        }
        else if (dx<0 && dy<0)  // 4. Quartal Winkkel von 0° - 89°
        {
            dWinkel = Math.toDegrees(rwinkel);
        }
        
        int iWinkel = (int)dWinkel;
        
        if (iWinkel == 360) 
        {
            iWinkel = 0;
        }
       
//         System.out.println("["+getX()+"|"+getY()+"]-["+otherP.getX()+"|"+otherP.getY()+"] "+dWinkel+"°");
        
        return iWinkel;
       
    }

Ein paar Hinweise noch:
über this.getX() und this.getY() bekommt man X und Y von P1.
genauso ist in otherP P2 drin.
Ich programmiere alles in Greenfoot (eine vereinfachte Entwicklungsumgebung für java) - das sollte hier aber kein Unterschied machen.

Jetzt zum Problem:

Die Funktion liefert mir für jeden Fall (außer 0,90,180,270) eindeutig falsche Werte. Sie liefert mir sogar meist einfach nur 180,0 oder 90,0 aus obwohl sich otherP immer verändert.

Ich bin jetzt schon 2 Tage an dieser Funktion - nach meinem besten Wissen müsste sie eigentlich funktionieren. Deshalb hoffe ich jetzt dass jemand der klüger ist als ich 😀 vielleicht sehen kann wo das Problem liegt.

Mit freundlichen Grüßen an jeden der sich das bis hier durchgelesen hat 🙂
Mike
 
Ich vermute, dass das das Problem ist:
Java:
double rwinkel = Math.atan(ady /adx);
Hier dividierst du 2 Integer, dann kommt auch wieder ein int dabei raus und wird abgerundet. Das heißt zum Beispiel, für
Code:
adx > ady
ist das Ergebnis der Division auf jeden Fall 0.
Probier mal
Java:
double rwinkel = Math.atan((double) ady / adx);
 
:toll: Danke Illuvatar :toll: ,
Das war's - wusste ich gar nicht das java das so eng nimmt (bin ja ein Umsteiger 😉 ).
Jetzt funktioniert's - die Drehung ist zwar noch um ab und zu 90°/180°/270° verschoben aber das bekomme ich selber hin.
Also dickes DANKE an dich 🙂
 
Ich weiß nicht, ob ich Deine Sonderfälle alle richtig verstehe. Kannst Du nicht einfach die Standardformel aus der Vektorrechnung verwenden und anschließend auswählen, ob Du 180 - Winkel oder 360 - Winkel etc. verwendest, je nach Sonderfall?

Edit: Hat sich dann wohl erledigt. 😉
 
Diese Winkelberechnung hat es ja in sich - nach mehreren Fehlversuchen habe ich gegooglet und bin hier gelandet. Danke für den Code!

Zum Testen hab ich eine kleine Main-Klasse geschrieben, die vielleicht dem einen oder anderen helfen mag:

Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class PaintTest extends JFrame {
	int sizeX = 600;
	int sizeY = 600;
	
	public static void main(String[] args) {
		new PaintTest();
	}
	
	public PaintTest() {
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setSize(sizeX, sizeY);
		setLocation(600,400);
		add(new DrawPanel());
		setVisible(true);
	}
	

	class DrawPanel extends JPanel {
		private static final long serialVersionUID = 1L;
		private int mouseX = 0;
		private int mouseY = 0;
		
		public DrawPanel() {
			setBackground(Color.WHITE);
			addMouseMotionListener(new MouseMotionListener() {
				public void mouseMoved(MouseEvent e) {
					mouseX = e.getX()-4;
					mouseY = e.getY()-14;
					repaint();
				}
				
				public void mouseDragged(MouseEvent e) {
				}
			});
	    }
		
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.fillOval(sizeX/2, sizeY/2, 8, 8); // mittelpunkt
	        
			// das testobjekt
			int angle = GeoUtils.getPointToPointAngle(sizeX/2, sizeY/2, mouseX , mouseY);
	        
			g.fillOval(mouseX, mouseY, 8, 8);
			g.drawString(""+angle, mouseX+12, mouseY);
		}
	}
}

Grüße,
Thomas
(der münchner, nicht der hambuger ;-)
 
Da ich keine Lust hatte, dafür eine Bibliothek zu installieren, war ich mal so frei, das etwas umzuschreiben. Dabei liegt bei mir - wie in der Mathematik - der Nullpunkt rechts auf der X-Achse. Aber seht selbst.

Java:
package graphicalUserInterface;


import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;


@SuppressWarnings("serial")
public class PaintTest extends JFrame {
    int sizeX = 600;
    int sizeY = 600;

    public static void main(String[] args) {
        new PaintTest();
    }

    public PaintTest() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(sizeX, sizeY);
        setLocation(600,400);
        add(new DrawPanel());
        setVisible(true);
    }


    class DrawPanel extends JPanel {
        private static final long serialVersionUID = 1L;
        private int mouseX = 0;
        private int mouseY = 0;

        public DrawPanel() {
            setBackground(Color.WHITE);
            addMouseMotionListener(new MouseMotionListener() {
                public void mouseMoved(MouseEvent e) {
                    mouseX = e.getX()-4;
                    mouseY = e.getY()-14;
                    repaint();
                }

                public void mouseDragged(MouseEvent e) {
                }
            });
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            /* Mauskoordinaten */
            int mouX = mouseX;
            int mouY = mouseY;

            /* Mittelpunkt-Koordinaten */
            int midX = sizeX/2;
            int midY = sizeY/2;

            /* Mittelpunkt zeichnen */
            g.fillOval(midX-5, midY-5, 10, 10);

            /* Punkt an Cursor zeichnen: */
            g.fillOval(mouX-5, mouY-5, 10, 10);

            /* Verbindungslinie zeichnen: */
            g.drawLine(midX, midX, mouX, mouY);

            /* Winkel berechnen: */
            long angle = calculateAngle(midX, midY, mouX, mouY);

            /* Winkel als Text darstellen: */
            g.drawString(Long.toString(angle), mouX+12, mouY);
        }

        /**
         * Winkelberechnung
         *
         *             (bx,by)
         *                *
         *               /|
         *              / |
         *          dz /  | dy
         *            /   |
         *           /g   |
         *  (ax,ay) *-----*
         *             dx
         *
         * @param ax x-Koordinate des Mittelpunktes
         * @param ay y-Koordinate des Mittelpunktes
         * @param bx x-Koordinate des Zielpunktes
         * @param by y-Koordinate des Zielpunktes
         *
         * @return Winkel
         */
        private long calculateAngle(int ax, int ay, int bx, int by) {
            if (ax == bx && ay == by)
                return 0;

            /* Berechnung der Seitenlängen des Dreiecks: */
            double dx = bx - ax;
            double dy = ay - by;
            double dz = Math.sqrt(dx*dx + dy*dy);

            /*
             * Berechnung des Winkels nach Pythagoras:
             *      sin(gamma) = dy/dz
             * <=>  gamma      = arcsin(dy/dz)
             */
            double gamma = Math.asin(dy / dz);

            /* Umrechnung von RAD auf DEG: */
            gamma = 180 * gamma / Math.PI;

            long angle = Math.round(gamma);

            /* erster Quadrant: */
            if (bx >= ax && by <= ay)
                ; /* passt schon so */
            /* zweiter Quadrant: */
            else if (bx <= ax && by <= ay)
                angle = 180 - angle;
            /* dritter Quadrant: */
            else if (bx <= ax && by >= ay)
                angle = 180 - angle;
            else if (bx >= ax && by >= ay)
                angle = 360 + angle;

            return angle;
        }
    }

}
 
Die Quadranten sind in der Mathematik normalerweise so eingeteilt: 1. oben rechts, 2. oben links, 3. unten links, 4. unten rechts. Wobei man rechts auf der x-Achse mit 0° anfängt, oben auf der y-Achse 90° erreicht, links auf der x-Achse 180° und so weiter, bis man von unten ankommend auf der x-Achse rechts dann 360° erreicht hat.


Edit: Ein Bild sagt mehr als viele Worte: Quadrant ? Wikipedia
 
Ähm, eigentlich willst Du doch nur sagen, dass Du die Drehung gegen den Uhrzeigersinn berechnest, so wie es am Einheitskreis üblich ist? "NullPUNKT rechts" hat mich verwirrt. 😉
 

Zurück
Oben