ANSI C: Απλοϊκό Παράδειγμα Buffered Γραφικών 2D

...του ubuntu και έργων ΕΛ/ΛΑΚ (Έργα-Οδηγοί-Προτάσεις)

Συντονιστής: konnn

ANSI C: Απλοϊκό Παράδειγμα Buffered Γραφικών 2D

Δημοσίευσηαπό migf1 » 10 Ιούλ 2011, 00:53

Μιας και είναι... μεγαλούτσικο για να μπει στο νήμα με τα παραδείγματα, το βάζω εδώ μόνο του (στο νήμα με τα παραδείγματα υπάρχει ήδη σε πολύ πιο απλή - ενδεχομένως πιο κατανοητή- έκδοση).

Το πρόγραμμα αποτελεί απλοϊκό παράδειγμα προγράμματος κονσόλας που παράγει στο 1ο καρτεσιανό τεταρτημόριο...
  • το γράφημα μιας συνάρτησης: f(x) = a*x + b
  • μια γραμμή μεταξύ δυο σημείων: (x1,y1) και (x2,y2)
  • έναν κύκλο με κέντρο στο σημείο: (x,y) και ακτίνα radius
  • μια έλλειψη που οριοθετείται από παραλληλόγραμμο με αντικριστές κορυφές τα σημεία: (x1,y1) πάνω αριστερά και (x2,y2) κάτω δεξιά
Επίσης παρακάμπτει πλήρως την scanf() για την είσοδο δεδομένων από τον χρήστη. Διαβάζει με την fgets() ολόκληρη τη γραμμή εισόδου σαν ένα string, την διασπάει σε όσα κομμάτια (tokens) χρειάζεται κάθε φορά, τα οποία και κατόπιν μετατρέπει σε αριθμούς (πραγματικούς ή ακέραιους, ανάλογα την περίσταση) με χρήση των συναρτήσεων atof() και atoi() (οι strtod() και strtol() είναι καλύτερες επιλογές, αλλά θα περιέπλεκαν ακόμα περισσότερο τον κώδικα).

Η συγκεκριμένη προσέγγιση εισόδου ελαχιστοποιεί (έως μηδενίζει) το πρόβλημα της scanf() με τα απομεινάρια στη γραμμή εισόδου λόγω line buffering. Έχει επίσης το επιπλέον ενδιαφέρον χαρακτηριστικό πως είναι πολύ εύκολο να καθορίσει κανείς ποιοι χαρακτήρες θα αγνοηθούν κατά την είσοδο, περνώντας τους σαν όρισμα στη συνάρτηση: s_tokenize() (αυτή είναι η συνάρτηση που κάνει τη διάσπαση σε tokens).

Για παράδειγμα, στο συγκεκριμένο πρόγραμμα, όταν σας ζητάει να του δώσετε τις συντεταγμένες x και y ενός σημείου, μπορείτε να πληκτρολογήσετε οτιδήποτε από τα παρακάτω:

Κώδικας: Επιλογή όλων

10 20
10,20
(10 20)
(10,20)

και αυτό θα κρατήσει μόνο τα νούμερα. Του έχω "πει" να αγνοεί παρενθέσεις, κόμματα, παύλες, κενά διαστήματα και tabs βάζοντας απλά αυτούς τους χαρακτήρες ως περιεχόμενα στο string: delims (δείτε τη συνάρτηση: exec_selected() ). Επίσης, απαιτεί να του δώσετε δυο νούμερα (αν του δώσετε μόνο ένα σας ξαναρωτάει).

Σε ότι αφορά τα γραφικά (που είναι σε text-mode), η ιδιαιτερότητα είναι πως δεν σχεδιάζονται σε πραγματικό χρόνο, αλλά μέσα σε ένα buffer που δεν είναι τίποτα άλλο από έναν 2-διάστατο πίνακα απλών χαρακτήρων (και συγκεκριμένα τον: Screen.pixel[ MAXROWS ][ MAXCOLS ] ). Για να τυπωθεί το γραφικό απλά τυπώνουμε όλους τους χαρακτήρες του buffer (συνάρτηση: draw_screen() ).

Η προσέγγιση αυτή είναι αναγκαία, διότι στην στάνταρ C δεν υπάρχει τρόπος να μετακινήσουμε ελεύθερα τον δρομέα σε όποιο σημείο της οθόνης θέλουμε. Υπάρχουν βέβαια cross-platform βιβλιοθήκες για γραφικά κονσόλας, με πιο δημοφιλή από όλες την curses, αλλά δεν ανήκει στις στάνταρ βιβλιοθήκες της γλώσσας.

Οπότε αναγκαστικά σχεδιάζουμε το γραφικό πρώτα στο buffer, μιας και στους πίνακες μπορούμε να έχουμε ελεύθερη πρόσβαση σε οποιοδήποτε στοιχείο τους, ανά πάσα στιγμή. Η σχεδίαση γίνεται "ανάβοντας" και "σβήνοντας" τα κατάλληλα pixels, που στη δική μας περίπτωση είναι οι θέσεις του πίνακα, με το κάθε "pixel" να είναι επί της ουσίας ένα char :)

Για "αναμμένα" pixels χρησιμοποιώ τον χαρακτήρα '#' και για "σβησμένα" τον χαρακτήρα '.' (μπορείτε να τους αλλάξετε πολύ εύκολα, αφού ορίζονται ως απλές σταθερές με #define στην αρχή του προγράμματος).

Βασικά μόνο "ανάβω" μεμονωμένα pixels, αφού πριν ξεκινήσω το κάθε γραφικό καλώ τη συνάρτηση: clear_screen() η οποία "σβήνει" μονομιάς όλα τα pixels του buffer.

Οι συναρτήσεις που "σχεδιάζουν" (που "ανάβουν" δηλαδή τα κατάλληλα pixels για κάθε σχήμα) είναι οι:
  • plot_f()
  • plot_line()
  • plot_circle()
  • plot_ellipse()
και όλες χρησιμοποιούν τη συνάρτηση: set_pixel() η οποία ανάβει ένα μεμονωμένο pixel (αυτό που ορίζουν οι συντεταγμένες που της περνάμε στα ορίσματά της).

Σε ότι αφορά τους μαθηματικούς αλγόριθμους που σχεδιάζουν τη γραμμή, τον κύκλο και την έλλειψη, χρησιμοποίησα τους πολύ διαδεδομένους για αυτές τις δουλειές Αλγόριθμους Bresenham, οι οποίοι είναι γρήγοροι μεν αλλά σε graphics mode παράγουν aliasing (για anti-aliased σχέδια όταν δουλεύετε σε graphics mode μπορείτε να χρησιμοποιήσετε τους Wu's Algorithms).

Σημειώστε πως τους αλγόριθμους Bresenham δεν τους έγραψα εγώ, αλλά χρησιμοποίησα έτοιμες & γρήγορες υλοποιήσεις τους, που βρήκα στο διαδίκτυο (έχω συμπεριλάβει τα σχετικά links στα σχόλια του κώδικα).

Τον κώδικα μπορείτε να το δείτε με syntax-highlighting και να τον κατεβάσετε από εδώ: http://ideone.com/psBzo

Δείγματα εξόδου:
Εικόνα
Εικόνα
Εικόνα
Εικόνα
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

  • ΣΧΕΤΙΚΑ ΘΕΜΑΤΑ
    ΑΠΑΝΤΗΣΕΙΣ
    ΠΡΟΒΟΛΕΣ
    ΣΥΓΓΡΑΦΕΑΣ

Επιστροφή στο Ανάπτυξη Λογισμικού / Αλγόριθμοι