C-Projekt, zurückgelegten Weg Auto plotten

makke306

Lt. Junior Grade
Registriert
Mai 2010
Beiträge
291
Hallo,
ich habe mir ein kleines C-Program geschrieben was Daten einliest und diese in der Konsole ausgibt (x,y-Daten). Es handelt sich um einen Pfad dass ein Auto in der 2D-Ebene fährt. Ich habe nun das Programm so geschrieben dass der zurückgelegte Weg geplottet wird so eine Art Simulation.

Was ich nicht verstehe ist dass der zurückgelegte Weg in der Konsole so "unruhig" geplottet wird. Also ich meine das ganze Feld blinkt immer so. Ich möchte es gerne haben dass da gar nichts "blinkt" und der Weg "smooth" geplottet wird. Hier ein Video damit man es versteht:

C:
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>

#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif

#define MAX_DATA_POINTS 200


typedef struct
{
    int x;
    int y;
} Point;

void clear_console()
{
#if defined _WIN32
    system("cls");
#elif defined(__LINUX__) || defined(__gnu_linux__) || defined(__linux__)
    (void)system("clear");
#elif defined(__APPLE__)
    (void)system("clear");
#else
    (void)system("clear");
#endif
}

void sleep_console(int ms)
{
#ifdef _WIN32
    Sleep((DWORD)(ms));
#else
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
#endif
    usleep(ms * 1000);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
}

int main()
{
    FILE *file = fopen("data.txt", "r");
    if (file == NULL)
    {
        printf("Error opening file.\n");
        return 1;
    }

    FILE *fpp = fopen("output.txt", "w");
    if (fpp == NULL)
    {
        printf("Error opening file.\n");
        return 1;
    }

    Point data[MAX_DATA_POINTS];
    int numPoints = 0;

    // read data into the struct array
    int x, y;
    while (fscanf(file, "%d,%d", &x, &y) == 2)
    {
        data[numPoints].x = x;
        data[numPoints].y = y;
        numPoints++;
    }

    fclose(file);

    // Find the maximum x and y values
    int maxX = data[0].x;
    int maxY = data[0].y;

    for (int i = 1; i < numPoints; i++)
    {
        if (data[i].x > maxX)
        {
            maxX = data[i].x;
        }
        if (data[i].y < maxY)
        {
            maxY = data[i].y;
        }
    }

    // Scale the values to fit the console window
    const int consoleWidth = 100;
    const int consoleHeight = 25;
    // scaling smaller so that data points fit into rectangular
    const int consoleWidth_smaller = consoleWidth+2;
    const int consoleHeight_smaller = consoleHeight-2;


    double scaleX = (float)consoleWidth_smaller / (maxX+90);
    double scaleY = (float)consoleHeight_smaller / (maxY-7);

    // Create a 2D array to represent the console window
    char plot[consoleHeight][consoleWidth];

    // Initialize the plot array with spaces
    for (int i = 0; i < consoleHeight; i++)
    {
        for (int j = 0; j < consoleWidth; j++)
        {
            plot[i][j] = ' ';
        }
    }

// Plot the data points on the array
    void plot_the_data_points_on_the_array(int count)
    {
        int lastYIndex=0;
        int xIndexOld = 0;

        for (int i = 0; i < count; i++)
        {

            int xIndex = (int)(data[i].x * scaleX+20);
            int yIndex = (int)(data[i].y * scaleY+1);
            if (i == 0)
            {
                plot[yIndex][xIndex] = '>';
                lastYIndex = yIndex;
            }
            else
            {

                plot[yIndex][xIndex] = '>';

                if ((lastYIndex != yIndex)  )
                {
                    plot[yIndex][xIndex] = 'v';
                }

                if ((xIndex < xIndexOld) )
                {
                    plot[yIndex][xIndex] = '<';
                }

                lastYIndex = yIndex;
                xIndexOld = xIndex;
            }
        }
    }
// Add the rectangular border
    void add_the_rectangular_border()
    {

        for (int i = 0; i < consoleWidth; i++)
        {
            plot[0][i] = '-';
            plot[consoleHeight - 1][i] = '-';
        }
        for (int i = 0; i < consoleHeight; i++)
        {
            plot[i][0] = '|';
            plot[i][consoleWidth - 1] = '|';
        }
    }

    char test[] ="       ";
    char test1[] ="   0   ";
    char test2[] ="  -200 ";
    // Print the plot array
    void print_the_plot_array()
    {
        for (int i = 0; i < consoleHeight; i++)
        {

            if(i==1)
            {
                printf("%s", test1);
            }
            else if(i==consoleHeight-2)
            {
                printf("%s", test2);
            }
            else if(i==(consoleHeight/2))
            {
                printf("%s","    y  ");
            }
            else
                printf("%s", test);

            for (int j = 0; j < consoleWidth; j++)
            {
                printf("%c", plot[i][j]);
                fprintf(fpp, "%c", plot[i][j]);
            }
            printf("\n");
            fprintf(fpp, "\n");
        }

        printf("   -30                                       x                   60 \n\n");
    }

    int count = 0;
    int xIndexalt=0;
    while(count <= (MAX_DATA_POINTS/2)-1)
    {

        clear_console();

        add_the_rectangular_border();
        plot_the_data_points_on_the_array(count);
        print_the_plot_array();

        sleep_console(60);


        count++;

    }

    fclose(fpp);


    return 0;
}
 

Anhänge

  • Video.mp4
    1,8 MB
Zuletzt bearbeitet:
Es gibt für Code extra Code Blöcke, bitte benutz die, dann wird der Code auch deutlich angenehmer zu lesen. Ich schau derweil mal ob mir was auffällt...ich kenn das Problem, erinnere mich nur grad nicht mehr woran genau das lag.
Ergänzung ()

Laut StackOverflow ist dein system("cls"); daran schuld. Schau da mal durch die Diskussion, da werden diverse Ansätze diskutiert und u.a. auch weiter auf Microsoft verwiesen, da solltest du ggf. deinen Algorithmus zum Zeichnen abändern. Passt auch zur Effizienz, du malst ja nur neue Zeichen rein und brauchst nicht bei jedem Pfeil alles neu malen.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: makke306 und NJay
In der while Schleife löschst Du permanent den gesamten Bildschirm mit „clear_console“.
Das Löschen des Bildschirms und das Zeichnen Deines Rahmens würde ich persönlich vor die Schleife ziehen.

Grüße T. N.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: DevD2016, Skysurfa und madmax2010
Die Funktion clear_console brauche ich ja in der Schleife damit immer das aktuelle Bild gezeichnet wird. Wenn ich das z.B. Außerhalb der while Schleife plaziere dann erhalte ich sozusagen sehr viele "Einzelbilder". Aber ich möchte ja so eine Art simulation haben. Das Zeichnen des Rahmen habe ich aus der Schleife genommen und es sieht etwas besser aus aber dennoch nicht so gut. Ich werde mal den Tipp von Nero1 anwenden und etwas recherchieren.
 
Zuletzt bearbeitet:
makke306 schrieb:
Das löschen mit clear_console brauche ich ja damit immer das aktuelle Bild gezeichnet wird
So wie du es bisher machst: ja. Aber du kannst auch die Herangehensweise ändern. Nur die betroffene Zeile neu malen, wenn möglich nur das geänderte Kästchen mit dem neuen Pfeil neu beschreiben, mit Puffern arbeiten wie in meinem Stackoverflow Link weiter oben...alles hat da so seine Vor- und Nachteile. Als meine WPF-App geflackert hat, habe ich es mit Double-Buffering oder wie das heißt beheben können. Aber das ist hier auch eher eine Symptombehandlung und nicht Ursachenbehebung, wenn es überhaupt geht.
 
  • Gefällt mir
Reaktionen: makke306 und Topinambur
Hallo, ich habe es nun mit der Windows Console API, mit der Funktion SetConsoleCursorPosition gelöst. Es sieht jetzt recht gut aus allerdings sehe ich immer den Cursor der sich dann hin und her bewegt. Kann ich den irgendwie ausblenden?
C:
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>

#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif

#define MAX_DATA_POINTS 200


typedef struct
{
    int x;
    int y;
} Point;

void clear_console()
{
#if defined _WIN32
    system("cls");
#elif defined(__LINUX__) || defined(__gnu_linux__) || defined(__linux__)
    (void)system("clear");
#elif defined(__APPLE__)
    (void)system("clear");
#else
    (void)system("clear");
#endif
}

void sleep_console(int ms)
{
#ifdef _WIN32
    Sleep((DWORD)(ms));
#else
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
#endif
    usleep(ms * 1000);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
}

void gotoxy(int x, int y)
{
    COORD c;
    c.X=x+7;
    c.Y=y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

int main()
{
    FILE *file = fopen("data.txt", "r");
    if (file == NULL)
    {
        printf("Error opening file.\n");
        return 1;
    }

    FILE *fpp = fopen("output.txt", "w");
    if (fpp == NULL)
    {
        printf("Error opening file.\n");
        return 1;
    }

    Point data[MAX_DATA_POINTS];
    int numPoints = 0;

    // read data into the struct array
    int x, y;
    while (fscanf(file, "%d,%d", &x, &y) == 2)
    {
        data[numPoints].x = x;
        data[numPoints].y = y;
        numPoints++;
    }

    fclose(file);

    // Find the maximum x and y values
    int maxX = data[0].x;
    int maxY = data[0].y;

    for (int i = 1; i < numPoints; i++)
    {
        if (data[i].x > maxX)
        {
            maxX = data[i].x;
        }
        if (data[i].y < maxY)
        {
            maxY = data[i].y;
        }
    }

    // Scale the values to fit the console window
    const int consoleWidth = 100;
    const int consoleHeight = 25;
    // scaling smaller so that data points fit into rectangular
    const int consoleWidth_smaller = consoleWidth+2;
    const int consoleHeight_smaller = consoleHeight-2;

    char test[] ="       ";
    char test1[] ="   0   ";
    char test2[] ="  -200 ";


    double scaleX = (float)consoleWidth_smaller / (maxX+90);
    double scaleY = (float)consoleHeight_smaller / (maxY-7);

    // Create a 2D array to represent the console window
    char plot[consoleHeight][consoleWidth];

    // Initialize the plot array with spaces
    for (int i = 0; i < consoleHeight; i++)
    {
        for (int j = 0; j < consoleWidth; j++)
        {
            plot[i][j] = ' ';
        }
    }

    // Add the rectangular border
    void add_the_rectangular_border()
    {

        for (int i = 0; i < consoleWidth; i++)
        {
            plot[0][i] = '-';
            plot[consoleHeight - 1][i] = '-';
        }
        for (int i = 0; i < consoleHeight; i++)
        {
            plot[i][0] = '|';
            plot[i][consoleWidth - 1] = '|';
        }
    }

    void plot_rectangular_border()
    {

        int x,y;

        for(y=0; y<consoleHeight; y++)
        {
            if(y==1)
            {
                printf("%s", test1);
            }
            else if(y==consoleHeight-2)
            {
                printf("%s", test2);
            }
            else if(y==(consoleHeight/2))
            {
                printf("%s","    y  ");
            }
            else
                printf("%s", test);

            for(x=0; x<consoleWidth; x++)
            {
                printf("%c",plot[y][x]);
            }
            printf("\n");

        }
        printf("   -30                                       x                   60 \n\n");
    }


    // Print the plot array
    // Plot the data points on the array
    void plot_the_data_points_on_the_array(int count)
    {
        int lastYIndex=0;
        int xIndexOld = 0;

        for (int i = 0; i < count; i++)
        {

            int xIndex = (int)(data[i].x * scaleX+20);
            int yIndex = (int)(data[i].y * scaleY+1);
            if (i == 0)
            {
                plot[yIndex][xIndex] = '>';
                gotoxy(xIndex, yIndex);
                printf("%c", plot[yIndex][xIndex]);
                lastYIndex = yIndex;
            }
            else
            {
                plot[yIndex][xIndex] = '>';
                gotoxy(xIndex, yIndex);
                printf("%c", plot[yIndex][xIndex]);
                sleep_console(1);

                if ((lastYIndex != yIndex)  )
                {
                    plot[yIndex][xIndex] = '>';
                    gotoxy(xIndex, yIndex);
                    printf("%c", plot[yIndex][xIndex]);
                    sleep_console(1);
                }

                if ((xIndex < xIndexOld) )
                {
                    plot[yIndex][xIndex] = '>';
                    gotoxy(xIndex, yIndex);
                    printf("%c", plot[yIndex][xIndex]);
                    sleep_console(1);
                }

                lastYIndex = yIndex;
                xIndexOld = xIndex;
            }

        }


    }

    int count_zeilen = 0;

    add_the_rectangular_border();
    plot_rectangular_border();


    if(count_zeilen < consoleHeight-1)
    {
        for(int i=1; i<consoleWidth-1; i++)
        {

            plot_the_data_points_on_the_array(MAX_DATA_POINTS/2);

            count_zeilen++;
        }

    }

    fclose(fpp);

    return 0;
}
 

Anhänge

  • Video2.mp4
    387,7 KB
  • Gefällt mir
Reaktionen: makke306
Hallo „makke306“,
da hast Du ja noch einmal ordentlich Gehirnsschmalz in Dein Projekt gesteckt.
Schön zu sehen, dass es erfolgreich und beinah zu Deiner vollständigen Zufriedenheit geworden ist.
Das Ausblenden des Cursors ist zwar lediglich kosmetischer Natur doch wäre es letztendlich die Kirsche auf der Sahne. Ich habe zwar keinen Tipp doch der Vorschlag von „CyborgBeta“ ist einen Versuch wert.

Grüße T. N.
 
  • Gefällt mir
Reaktionen: makke306
Zurück
Oben