Merkez noktası, yarıçapı ve derecesi verilen bir daire üzerindeki noktayı bulun


84

Böyle bir matematik yapmayalı 10 yıl oldu ... 2 boyutlu bir oyun programlıyorum ve bir oyuncuyu hareket ettiriyorum. Oynatıcıyı hareket ettirirken, -360 ile 360 ​​arasında pozitif VEYA negatif bir açı (derece) verildiğinde, oyuncunun konumundan 200 piksel uzaklıkta bir daire üzerinde noktayı hesaplamaya çalışıyorum. Ekran 1280x720'dir ve 0,0 merkez noktasıdır ekranın. Oyuncu tüm bu Kartezyen koordinat sistemi etrafında hareket eder. Bulmaya çalıştığım nokta ekran dışı olabilir.

Yarıçap ve açı ile noktayı bulma makalesindeki formülleri denedim ama "Açı" nın ne olduğunu anladığıma inanmıyorum çünkü Açı'yı -360 ila 360 olarak bir Cos (açı) veya Sin'e geçirdiğimde garip sonuçlar alıyorum (açı).

Yani örneğin benim ...

  • Kartezyen düzlemde 1280x720
  • Merkez Nokta (oyuncunun pozisyonu):
    • let x = minimum -640 ile maksimum 640 arasında bir sayı
    • y = minimum -360 ile maksimum 360 arasında bir sayı olsun
  • Oyuncunun etrafındaki Çemberin Yarıçapı: r her zaman = 200 olsun
  • Açı: a = -360 ile 360 ​​arasında verilen bir sayı olsun (negatifin aşağıya veya pozitifin yukarı doğru işaret etmesine izin verin, böylece -10 ve 350 aynı cevabı verecektir)

Daire üzerinde X'i döndürmenin formülü nedir?

Çemberde Y'yi döndürmenin formülü nedir?

görüntü açıklamasını buraya girin görüntü açıklamasını buraya girin


16
Bu İYİ bir soru !!! +1
FrostyFire

1
Soru: Çoğu oyunda sol üstte 0,0'a koordinat yok mu? ve y ekseni aşağı iniyor, yukarı değil mi?
Persijn

Yanıtlar:


74

Bağlantınızdaki basit denklemler, çemberin merkezine göre çember üzerindeki noktanın X ve Y koordinatlarını verir .

X = r * cosine(angle)  
Y = r * sine(angle)

Bu size noktanın dairenin merkezinden ne kadar uzakta olduğunu söyler. Merkezin koordinatlarına (Cx, Cy) sahip olduğunuz için, hesaplanan ofseti eklemeniz yeterlidir.

Çember üzerindeki noktanın koordinatları:

X = Cx + (r * cosine(angle))  
Y = Cy + (r * sine(angle))

1
Benim kafa karışıklığım ilk olarak ANGLE ve DEGREE arasındaki farkla ilgiliydi. Aynı şey olduklarını sanıyordum. Sonra düzlemde (x, y) noktasını aldığımı düşündüm ama aslında x ve y'nin kenarlarının uzunluğunu alıyordum. Bunu kağıda çizdim, sonra formülleri kontrol etmek için derece aralığını kapsayacak şekilde excel'e yerleştirdim. Şimdi benim kodumda çalışıyor.
Kyle Anderson

3
Olmamalıdır X = xcircle + (r * sine(angle))olması X = xcircle + (r * cosine(angle))(ve tam tersi Y)?
txtechhelp

4
Açının radyan cinsinden bir değer olması gerektiğine dikkat edin!
Roman M

17

Kullandığınız kodu yazmalısınız. Bu, sorunun tam olarak belirlenmesine yardımcı olur.

Bununla birlikte, açınızı -360 ile 360 ​​arasında ölçmekten bahsettiğiniz için, muhtemelen matematik kitaplığınız için yanlış birimleri kullanıyorsunuzdur. Trigonometri fonksiyonlarının çoğu uygulaması, girdileri için radyan kullanır. Ve bunun yerine dereceleri kullanırsanız ... cevaplarınız garip bir şekilde yanlış olacaktır.

x_oncircle = x_origin + 200 * cos (degrees * pi / 180)
y_oncircle = y_origin + 200 * sin (degrees * pi / 180)

Kadranın beklediğiniz gibi olmadığı bir durumla da karşılaşabileceğinizi unutmayın. Bu, sıfır açısının nerede olduğunu dikkatlice seçerek veya beklediğiniz çeyreği manuel olarak kontrol ederek ve sonuç değerlerine kendi işaretlerinizi uygulayarak düzeltilebilir.


1
Bu gerçekten bir cevaptan ziyade bir yorum olmalıdır. Ancak, radyan ve dereceler hakkında iyi bir yakalama.
yoozer8

Zombi gönderisi sorusu: parens içinde, bu mu (deg * (pi / 180))yoksa başka bir yol ((deg * pi) / 180)mu? Ayrıca rad ile derece arasındaki farkı belirlediğiniz için teşekkür ederiz.
monsto

@monsto zombileri hala bildirim gönderiyor. :). Çarpma ve bölme değişmeli gösterimler olduğundan içteki parenlerin önemi yoktur. Wolfram.com/… . Koduma aşırı parantez koyduğum için uzun süredir suçluyum. Açıklık istiyormuş gibi yapıyorum ama bu kesinlikle doğru değil, yoksa bundan rahatsız olmazdın.
Seth Battin

6

Bu tür manipülasyonlar için matrislerin kullanılmasını şiddetle öneririm. Bu en genel yaklaşımdır, aşağıdaki örneğe bakın:

// The center point of rotation
var centerPoint = new Point(0, 0);
// Factory method creating the matrix                                        
var matrix = new RotateTransform(angleInDegrees, centerPoint.X, centerPoint.Y).Value;
// The point to rotate
var point = new Point(100, 0);
// Applying the transform that results in a rotated point                                      
Point rotated = Point.Multiply(point, matrix); 
  • Yan not, kongre açıyı saat yönünün tersine ölçmektir (pozitif) X ekseni

5

Açıyı -360 ila 360 olarak bir Cos (açı) veya Sin (açı) olarak geçirdiğimde garip sonuçlar alıyorum.

Sanırım girişiminizin işe yaramamasının nedeni, açıları derece cinsinden geçmenizdir. sinVe cossayılar uzak olmalıdır böylece trigonometrik fonksiyonlar, radyan cinsinden ifade açıları bekliyoruz 0etmek 2*M_PI. Dereceler için dgeçersiniz M_PI*d/180.0. başlıkta M_PItanımlanan bir sabittir math.h.


Açı ve derecenin muhtemelen aynı şey olmadığını düşündüm, bu yüzden Açı = M_PI * d / 180.0 derken doğru muyum burada d, -360 ile 360 ​​arasında bir sayı olabilir veya başka bir adıma ihtiyacım var mı?
Kyle Anderson

1
@Kyle dila 0için 360ya da gelen -180için 180değil, (a tam bir daire) -360ile 360(iki tam daireler).
Sergey Kalinichenko

4

Bir saatin kollarının kodlu hareketini oluşturmak için buna da ihtiyacım vardı. Birkaç formül denedim ama işe yaramadı, bu yüzden bulduğum şey buydu:

  • hareket - saat yönünde
  • puan - her 6 derecede bir (çünkü 360 derece 60 dakikaya bölünmüş 6 derecedir)
  • el uzunluğu - 65 piksel
  • merkez - x = 75, y = 75

Böylece formül şöyle olurdu

x=Cx+(r*cos(d/(180/PI))
y=Cy+(r*sin(d/(180/PI))

burada x ve y bir dairenin çevresindeki noktalardır, Cx ve Cy merkezin x, y koordinatlarıdır, r yarıçaptır ve d derece miktarıdır.


2

İşte c # uygulaması. Yöntem alır dairesel noktalar döndürür radius, centerve angle intervalparametre olarak. Açı Radyan olarak geçilir.

public static List<PointF> getCircularPoints(double radius, PointF center, double angleInterval)
        {
            List<PointF> points = new List<PointF>();

            for (double interval = angleInterval; interval < 2 * Math.PI; interval += angleInterval)
            {
                double X = center.X + (radius * Math.Cos(interval));
                double Y = center.Y + (radius * Math.Sin(interval));

                points.Add(new PointF((float)X, (float)Y));
            }

            return points;
        }

ve arama örneği:

List<PointF> LEPoints = getCircularPoints(10.0f, new PointF(100.0f, 100.0f), Math.PI / 6.0f);

Yuvarlama hataları nedeniyle bunun beklenenden 1 daha az öğe döndürebileceğine DİKKAT EDİN! bu nedenle, sonunda doğru miktarda öğe alabilmek için biraz maring ekledim (örneğimde double yerine floats var); for (float interval = angleInterval; interval <2 * Math.PI + 0.0000099f; interval + = angleInterval)
sommmen

1

Yukarıdaki katkılarınızın bir Arduino LCD pusulası üretmeme nasıl yardımcı olduğunu paylaşmak istedim. Umarım bu doğru görgü kurallarıdır ... Stackoverflow'a yeni katıldım, böylece siz değerli milletlere teşekkür edebilirim.

Yukarıdaki geometri devlerinin omuzlarında dururken bu örnek pusulayı üretmeyi başardım: Birden çok yatak içeren Arduino TFT pusulası

Tekrar tekrar çağırdığım işlevin kodu (minik sarı metinde gördüğünüz farklı rulmanlar için) Arduino ile yazılmıştır ("C" gibi) ... ve oldukça çevrilebilir:

void PaintCompassNeedle( int pBearingInDegrees, int pRadius, TSPoint pCentrePt ) {
    // ******************************************************************************
    // * Formula for finding pointX on the circle based on degrees around the circle:
    // * x_oncircle = x_origin + radius * cos (degrees * pi / 180)  
    // * y_oncircle = y_origin - radius * sin (degrees * pi / 180) //minus explained
    // * Thanks to folks at stackoverflow...standing on the shoulders of giants. :) 

    float bearingInRads = (pBearingInDegrees) * PI / 180; 
    // Degrees vs Rads...The math folks use Rads in their formulas

    // *******************************************************************
    // * bearingPt is the point on the circle that we are trying to find
    TSPoint bearingPt;
    // Find the X on the circle starting with orgin (centre)
    bearingPt.x = pCentrePt.x + pRadius * sin(bearingInRads); 
    // Notice the "minus" R * cos()...because TFT the y is upside down bearingPt.y = 
    pCentrePt.y - pRadius * cos(bearingInRads); 
    // * Extra Explanation: The TFT is the graphical display I'm using and it
    // * calculates x & y from the top left of screen (portrait mode) as (0,0)
    // * ...so by Subtracting from the Y orgin...I flip it vertically
    // * Other folks using x,y as increasing to the right and up respectively
    // * would keep the plus sign after the pCentrePt.y
    // *************************************************************************

    // ***************************************************************
    // * This part will change for the final product...but leaving
    // * it because when call numerous times it shows it working for
    // * a number of different quadrants (displaying yellow degrees text)
    tft.fillCircle( bearingPt.x, bearingPt.y, 5, RED); 
    tft.setCursor( bearingPt.x, bearingPt.y );
    tft.setTextSize( 1 );
    tft.setTextColor( YELLOW );
    tft.print( pBearingInDegrees );

    TSPoint innerPt;
    innerPt.x = pCentrePt.x + pRadius/2 * sin(bearingInRads);
    innerPt.y = pCentrePt.y - pRadius/2 * cos(bearingInRads);
    tft.drawLine(innerPt.x, innerPt.y, bearingPt.x, bearingPt.y, RED);

}

0

Cevap tam tersi olmalıdır.

X = Xc + rSin (açı)

Y = Yc + rCos (açı)

burada Xc ve Yc çemberin merkez koordinatlarıdır ve r, yarıçaptır.


0

Önermek:

 public static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 
pivot, Vector3 angles)
    {
	    return Quaternion.Euler(angles) * (point - pivot) + pivot;
    }


-3

Bunu kullanabilirsiniz:

Çember denklemi nerede

(xk) 2 + (yv) 2 = R 2

burada k ve v sabittir ve R yarıçaptır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.