Punkte einer Linie im Koordinatensystem errechnen



  • Hi,

    ich bin gerade dabei, mit nem Kumpel ne CNC Fräse zu bauen. Dazu muss ich alle Punkte einer Linie zwischen zwei Koordinaten errechnen. Die Daten will ich dann in einem 2 Mehrdimensionale Array speichern. Die Werte benötige ich mit 3 Nachkommastellen.
    Die X Werte sollen bei dem Array in der 1. Zeile gespeichert werden.
    Beispiel:

    Linie zwischen (0|0) und (1|1)
    float punkte[][] = {0.000,0.001,0.002,0.003,usw.,0.01,usw.,0.999},    //x Werte
                       {0.000,0.001,0.002,0.003,usw.,0.01,usw.,0.999};    //y Werte
    Das ist natürlich ein einfaches Beispiel. Es sollen dann Werte wie z.B.:
    X 15.002  Y 9.982
    X 18.329  Y 24.691
    berechnet werden.
    

    Könnt ihr mir helfen? Wie macht man das am besten?

    MfG
    Philipp



  • Was willst du jetzt wissen? Wie man ein Array erstellt? Wie man Werte interpoliert?



  • Alle Punkte der Geraden durch (0|0) und (1|1) sind
    (0|0) + x * (1|1)

    Alle Punkte der Geraden durch A und B sind
    A + x * (B-A)

    Wie man sich leicht denken kann, sind das beliebig viele Punkte.



  • Aso sorry, hab ich nicht genau geschrieben.
    Ich möchte wissen, wie man am besten alle Werte zwischen diesen 2 Punkten erstellt.
    Alle Punkte bis auf eine Genauigkeit von 3 Nachkommastellen.
    Also: P1 = (0|0), P2 = (1|1)
    Alle Punkte dazwischen:
    (0,001|0,001)
    (0,002|0,002)
    usw.

    MfG



  • class point{
    // ... 
    float x, y;
    }
    
    void f()
    {
      point A(0,0), B(1,1);
      point AB = B-A;
      vector<point> linie;
      float f = 0.001F / std::max(AB.x, AB.y);
      for(float x=0; x <= 1; x+=f)
        linie.push_back(A + x*AB);
    }
    

    Ist nicht getestet und nicht besonders durchdacht (zB wird man wahrscheinlich nicht genau bei B ankommen).
    Für die Klasse point sind Konstruktor und +,*,- Operatoren angenommen.



  • Ok, danke schonmal.
    Ich habe gerade den Bresenham Algorithmus gefunden. Ich habe leider weder in Mathe noch beim Programmieren damit gearbeitet.
    http://www.codekeep.net/snippets/e39b2d9e-0843-4405-8e31-44e212ca1c45.aspx
    Da hat jemand eine Funktion dafür geschrieben, aber leider gibt, werden die Punkte da auch nur in int berechnet und nicht in float. Weiß jemand, wie ich die Funktiom umschreiben kann, damit ich alle Punkte auf 3 Nachkommastellen bekomme?
    Also (0.001|0.001),(0.002|0.002) usw.?

    MfG



  • lord-maricek schrieb:

    Ok, danke schonmal.
    Ich habe gerade den Bresenham Algorithmus gefunden. Ich habe leider weder in Mathe noch beim Programmieren damit gearbeitet.

    Du könntest einfach in 1/1000 rechnen. Ich nehme an, die Einheit der Längen ist mm, so müsstest Du halt in μm rechnen.

    Es ist aber hier gar nicht nötig; der Bresenham Algorithmus wurde entwickelt um Graphik schneller zu machen. Deine CNC-Fräse wird nie so schnell sein, dass ein 0815-PC von heute da nicht mitkommt, auch wenn er für jeden μm einen neuen Wert berechnen musst. Auch ist der Bresenham Algorithmus nicht dafür geeignet eine CNC-Fräse zu steuern, da die absolute Schrittweite sich mit der Schrittrichtung um bis zu 41% ändern würde. Das ist sicher nicht erwünscht.
    Besser Du bleibst bei float (oder besser Datentyp double) und rechnest weiter in mm.

    brotbernd hat Dir schon die notwendigen Informationen gegeben. Hilfreich ist eine Klasse Point bzw. Vektor (im mathematischen Sinne), Beispiele für Vektor in C++ gibt es genug, dann sähe das etwa so aus:

    #include <iostream>
    #include <iomanip> // setprecision
    #include <cmath> // std::sqrt
    
    class Vektor
    {
    public:
        Vektor() : m_x(0), m_y(0) {}
        Vektor( double x, double y ) 
            : m_x(x), m_y(y) 
        {}
        Vektor& operator+=( const Vektor& b )
        {
            m_x += b.m_x; m_y += b.m_y;
            return *this;
        }
        Vektor& operator-=( const Vektor& b )
        {
            m_x -= b.m_x; m_y -= b.m_y;
            return *this;
        }
        Vektor& operator*=( double fac )
        {
            m_x *= fac; m_y *= fac;
            return *this;
        }
        Vektor& operator/=( double div )
        {
            return *this *= 1/div;
        }
    
        // --   Länge
        friend double abs( const Vektor& v )
        {
            return std::sqrt( v.m_x * v.m_x + v.m_y * v.m_y );
        }
        // --   Access
        friend double X( const Vektor& v ) { return v.m_x; }
        friend double Y( const Vektor& v ) { return v.m_y; }
    
        // --   Ausgabe
        friend std::ostream& operator<<( std::ostream& out, const Vektor& v )
        {
            return out << "(" << v.m_x << "|" << v.m_y << ")";
        }
    private:
        double m_x, m_y;
    };
    
    Vektor operator+( Vektor a, const Vektor& b )
    {
        return a += b;
    }
    Vektor operator-( Vektor a, const Vektor& b )
    {
        return a -= b;
    }
    Vektor operator*( Vektor v, double fac )
    {
        return v *= fac;
    }
    Vektor operator*( double fac, Vektor v )
    {
        return v *= fac;
    }
    Vektor operator/( Vektor v, double div )
    {
        return v /= div;
    }
    
    int main()
    {
        using namespace std;
        const double schrittweite = 1./1000; // 1/1000 mm
        Vektor start( 15.002, 9.982 );
        Vektor ende( 18.329, 24.691 );
    
        Vektor richtung = ende - start;
        int anzSchritte = int( abs( richtung ) / schrittweite + 0.5 ); // + 0.5 dient der korrekten Rundung
        Vektor schritt = richtung / anzSchritte; // ein Schritt mit der Länge 'schrittweite'
        cout << fixed << setprecision(3); // sorgt dafür, dass die double mit 3 Nachkommastellen geschrieben werden
        int i = 0;
        for( Vektor pos = start; i <= anzSchritte; ++i, pos = start + i*schritt )
        {
            cout << pos << endl;
        }
        return 0;
    }
    

    Ich habe die komplette Implementierung von Vektor auch gepostet, da ist jetzt auch nichts besonderes dabei. Du solltest zunächst versuchen zu verstehen, was im main passiert.
    Wichtig bei der Realisierung ist noch, dass Du keine Fließkommazahlen aufsummierst, weil das sonst zu Rundungsfehlern führt. Deshalb auch der int in der Schleife.

    Die Ausgabe ist:

    (15.002|9.982)
    (15.002|9.983)
    (15.002|9.984)
    (15.003|9.985)
    (15.003|9.986)
    (15.003|9.987)
    (15.003|9.988)
    (15.004|9.989)
    (15.004|9.990)
    (15.004|9.991)
    ...
    (18.327|24.682)
    (18.327|24.683)
    (18.327|24.684)
    (18.328|24.685)
    (18.328|24.686)
    (18.328|24.687)
    (18.328|24.688)
    (18.329|24.689)
    (18.329|24.690)
    (18.329|24.691)
    

    Das sollte das sein, was Du gewünscht hast.

    Gruß
    Werner

    @Edit: Referenz bei operator= vergessen


Anmelden zum Antworten