Το πρόγραμμα αποτελεί απλοϊκό παράδειγμα προγράμματος κονσόλας που παράγει στο 1ο καρτεσιανό τεταρτημόριο...
- το γράφημα μιας συνάρτησης: f(x) = a*x + b
- μια γραμμή μεταξύ δυο σημείων: (x1,y1) και (x2,y2)
- έναν κύκλο με κέντρο στο σημείο: (x,y) και ακτίνα radius
- μια έλλειψη που οριοθετείται από παραλληλόγραμμο με αντικριστές κορυφές τα σημεία: (x1,y1) πάνω αριστερά και (x2,y2) κάτω δεξιά
Η συγκεκριμένη προσέγγιση εισόδου ελαχιστοποιεί (έως μηδενίζει) το πρόβλημα της 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()
Σε ότι αφορά τους μαθηματικούς αλγόριθμους που σχεδιάζουν τη γραμμή, τον κύκλο και την έλλειψη, χρησιμοποίησα τους πολύ διαδεδομένους για αυτές τις δουλειές Αλγόριθμους Bresenham, οι οποίοι είναι γρήγοροι μεν αλλά σε graphics mode παράγουν aliasing (για anti-aliased σχέδια όταν δουλεύετε σε graphics mode μπορείτε να χρησιμοποιήσετε τους Wu's Algorithms).
Σημειώστε πως τους αλγόριθμους Bresenham δεν τους έγραψα εγώ, αλλά χρησιμοποίησα έτοιμες & γρήγορες υλοποιήσεις τους, που βρήκα στο διαδίκτυο (έχω συμπεριλάβει τα σχετικά links στα σχόλια του κώδικα).
Τον κώδικα μπορείτε να το δείτε με syntax-highlighting και να τον κατεβάσετε από εδώ: http://ideone.com/psBzo
Δείγματα εξόδου:





