De hoek berekenen tussen de lijn gedefinieerd door twee punten

Ik ben momenteel bezig met het ontwikkelen van een eenvoudig 2D-spel voor Android. Ik heb een stilstaand object in het midden van het scherm en ik probeer dat object te laten draaien en naar het gebied op het scherm te wijzen dat de gebruiker aanraakt. Ik heb de constante coördinaten die het midden van het scherm vertegenwoordigen en ik kan de coördinaten krijgen van het punt waarop de gebruiker tikt. Ik gebruik de formule die in dit forum wordt beschreven: Hoe krijg ik een hoek tussen twee punten?

  • Er staat het volgende: “Als u de hoek wilt tussen de lijn die wordt gedefinieerd door deze twee punten en de horizontale as:

    double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
    
  • Ik heb dit geïmplementeerd, maar ik denk dat het feit dat ik in schermcoördinaten werk een misrekening veroorzaakt, aangezien de Y-coördinaat omgekeerd is. Ik weet niet zeker of dit de juiste manier is om het aan te pakken, andere gedachten of suggesties worden op prijs gesteld.


Antwoord 1, autoriteit 100%

Aannames: Xis de horizontale as, en neemt toe bij beweging van links naar rechts.
Yis de verticale as en neemt toe van onder naar boven. (touch_x, touch_y)is de
door de gebruiker gekozen punt. (center_x, center_y)is het punt in het midden van de
scherm. thetawordt tegen de klok in gemeten vanaf de as +x. Dan:

delta_x = touch_x - center_x
delta_y = touch_y - center_y
theta_radians = atan2(delta_y, delta_x)

Bewerken: je hebt in een opmerking vermeld dat y van boven naar beneden toeneemt. In dat
geval,

delta_y = center_y - touch_y

Maar het zou juister zijn om dit te omschrijven als (touch_x, touch_y)
in poolcoördinaten ten opzichte van (center_x, center_y). Zoals ChrisF al zei,
het idee om een “hoek tussen twee punten” te nemen is niet goed gedefinieerd.


Antwoord 2, autoriteit 36%

Ik had zelf behoefte aan vergelijkbare functionaliteit, dus na veel haren trekken kwam ik op de onderstaande functie

/**
 * Fetches angle relative to screen centre point
 * where 3 O'Clock is 0 and 12 O'Clock is 270 degrees
 * 
 * @param screenPoint
 * @return angle in degress from 0-360.
 */
public double getAngle(Point screenPoint) {
    double dx = screenPoint.getX() - mCentreX;
    // Minus to correct for coord re-mapping
    double dy = -(screenPoint.getY() - mCentreY);
    double inRads = Math.atan2(dy, dx);
    // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12 O'clock
    if (inRads < 0)
        inRads = Math.abs(inRads);
    else
        inRads = 2 * Math.PI - inRads;
    return Math.toDegrees(inRads);
}

Antwoord 3, autoriteit 26%

Een paar antwoorden hier hebben geprobeerd het “scherm”-probleem uit te leggen waarbij top left0,0is en bottom rightis (positief ) screen width, screen height. De meeste rasters hebben de Y-as als positief boven Xen niet onder.

De volgende methode werkt met schermwaarden in plaats van “raster”-waarden. Het enige verschil met het uitgezonderde antwoord is dat de Y-waarden worden omgekeerd.

/**
 * Work out the angle from the x horizontal winding anti-clockwise 
 * in screen space. 
 * 
 * The value returned from the following should be 315. 
 * <pre>
 * x,y -------------
 *     |  1,1
 *     |    \
 *     |     \
 *     |     2,2
 * </pre>
 * @param p1
 * @param p2
 * @return - a double from 0 to 360
 */
public static double angleOf(PointF p1, PointF p2) {
    // NOTE: Remember that most math has the Y axis as positive above the X.
    // However, for screens we have Y as positive below. For this reason, 
    // the Y values are inverted to get the expected results.
    final double deltaY = (p1.y - p2.y);
    final double deltaX = (p2.x - p1.x);
    final double result = Math.toDegrees(Math.atan2(deltaY, deltaX)); 
    return (result < 0) ? (360d + result) : result;
}

Antwoord 4

“de oorsprong bevindt zich in de linkerbovenhoek van het scherm en de Y-coördinaat neemt toe naar beneden, terwijl de X-coördinaat naar rechts toeneemt zoals normaal. Ik denk dat mijn vraag wordt, moet ik de schermcoördinaten omrekenen naar cartesiaanse coördinaten voordat u de bovenstaande formule toepast?”

Als u de hoek zou berekenen met behulp van cartesiaanse coördinaten en beide punten in kwadrant 1 zouden zijn (waarbij x>0 en y>0), zou de situatie identiek zijn aan de pixelcoördinaten op het scherm (behalve het omgekeerde Y-ding Als je Y negeert om het met de goede kant naar boven te krijgen, wordt het kwadrant 4…). Het converteren van schermpixelcoördinaten naar Cartesiaans verandert de hoek niet echt.


Antwoord 5

in Android deed ik dit met kotlin:

private fun angleBetweenPoints(a: PointF, b: PointF): Double {
        val deltaY = abs(b.y - a.y)
        val deltaX = abs(b.x - a.x)
        return Math.toDegrees(atan2(deltaY.toDouble(), deltaX.toDouble()))
    }

Antwoord 6

met pygame:

dy = p1.y - p2.y
dX = p2.x - p1.x
rads = atan2(dy,dx)
degs = degrees(rads)
if degs < 0 :
   degs +=90

het werkt voor mij


Antwoord 7

fun calculateAngle(
    touchX: Float,
    touchY: Float,
    centerX: Float,
    centerY: Float
): Float {
    val deltaX = centerX - touchX
    val deltaY = centerY - touchY
    return Math.toDegrees(atan2(deltaY.toDouble(), deltaX.toDouble())).toFloat()
}

Deze functie retourneert een waarde zoals

Als we + 180naar de retourwaarde gaan, krijgen we de waarde van rechts naar linkszoals

360(<=> 0) -> 45 -> 90 -> 135 -> 180 -> 225 -> 270 -> 315

vergelijkbaar met de hoek wanneer we drawArc

Other episodes