Προς το περιεχόμενο

Qt σχεδίαση γραμμών σε σχέση με τη θέση του ποντικιού


karabouzouk...

Προτεινόμενες αναρτήσεις

Δημοσ.
Το πρόβλημα ήταν να περνάνε τα κλίκ από την εφαρμογή με τα σχήματα στις πίσω εφαρμογές.. δλδ κάτι σαν τζάμι που έχει τα σχέδια και περνάνε μόνο τα κλικ από μεσα του..

 

τελικά έγινε λειτουργική η εφαρμογή.. έχω φτιάξει μόνο ένα δεξιό τοίχο..

Βάζω τον κώδικα μήπως κάποιος έχει πολύ χρόνο και δεν ξέρει τι να τον κάνει ώστε να τον βελτιώσει..[..][/code]

Ωραίος, η διαφάνεια ειδικά σε Linux (X-Windows) όπως διαπίστωσες ταλαιπωρεί πολύ κόσμο :-)

 

Υ.Γ.

Όσον αφορά την χρησιμότητα του κτλ, απλά υπενθυμίζω ένα παλιό ρητό:

 

One man's trash is another man's treasure

  • Απαντ. 73
  • Δημ.
  • Τελ. απάντηση
Δημοσ.
Εγώ μελετάω την Qt τον τελευταίο καιρό όταν έχω χρόνο και με ενδιαφέρει να δω ιδέες.

Αλλά δεν καταλαβαίνω που μπορεί να χρησιμεύσει κάτι σαν αυτό που έφτιαξες.

Πέραν της τεχνικής με την διαφάνεια (που κι' αυτή δεν έχει άμεση πρακτική χρησιμότητα),

μου φαίνεται παντελώς άχρηστο.

 

Πάντως, σε ότι αφορά το γεωμετρικό μέρος, γενίκευση των ανακλάσεων σε διαγώνιους τοίχους γίνεται με την διανυσματική σχέση που έδωσα.

Η δυσκολία είναι μόνον να βρεθεί το κάθετο διάνυσμα n της ευθείας (βλ. αναλυτική γεωμετρία).

 

Για τη χρησιμότητα δεν θα σου πω ότι έχεις άδικο αλλά όλο και κάποιος μπορεί να χρειαστεί κάτι παρόμοιο.. για μένα είναι χρήσιμο πρώτον γιατί έψαχνα αφορμή για να εξασκηθώ με την Qt και το συγκεκριμένο για μένα είναι χρήσιμο για υπολιγισμό σε διάφορα παιχνίδια όπως το Bubble bubble (αν θυμαστε από mame32) που απαιτούν καλό στοχο και υπολογισμό που θα πάει η μπάλα μετά από σπόντα σε τοίχο..

 

 

Ωραίος, η διαφάνεια ειδικά σε Linux (X-Windows) όπως διαπίστωσες ταλαιπωρεί πολύ κόσμο :-)

 

Υ.Γ.

Όσον αφορά την χρησιμότητα του κτλ, απλά υπενθυμίζω ένα παλιό ρητό:

 

One man's trash is another man's treasure

 

Η χρησιμότητα ήταν κυρίος η εξάσκηση..!!! και όντως ισχύει το ρητό..!

 

αν το τρέξει κανείς σε windows ας μας πει αν δουλεύει η όχι..! και αν δουλεύουν και αυτά τα κλικ που περνάνε τα παράθυρα ορίζωντας τα flags..

Δημοσ.

Σε windows που το δοκίμασα χωρίς να πειράξω κάτι (copy - paste), δεν βλέπω αυτό που δείχνεις εδώ.

 

Η οθόνη γίνεται μαύρη και στην θέση του cursor υπάρχει ένα διαφανές τετραγωνάκι.

Κουνώ το ποντίκι και το τετραγωνάκι κινείται αφήνοντας να φανεί τι υπάρχει από κάτω.

Aλληλεπίδραση από κάτω υπάρχει. Ακτίνα και ανακλάσεις δεν υπάρχουν ή δεν φαίνονται.

(Μήπως όταν ανοίγει το παράθυρο δεν έχει οριστεί χρώμα background και χρησιμοποιεί ως default το μαύρο ; )

 

Εν πάση περιπτώση δεν έχω χρόνο τώρα να το ψάξω περισσότερο.

Πήρα κάποιες ιδέες πάντως για πράγματα που δεν αναφέρονται άμεσα αλλού (full screen, διαφάνεια κλπ) και ως εκ τούτου σε ευχαριστώ που διέθεσες τον πλήρη κώδικα.

Αν κάνεις κι άλλα παρόμοια, βάλτα διότι επειδή θέλω να ασχοληθώ με την Qt θα μου χρειαστούν...

Δημοσ.

μολις εγκαταστήσω το Qt στα windows θα προσπαθήσω να το κάνω να δουλέψει και εκεί..

Αν θέλεισ δοκίμασε να βγάλεις τη γραμμή w1.setAttribute(Qt::WA_TranslucentBackground);

η οποία κάνει διάφανο το παράθυρο και αφίνει μόνο το σχέδιο να φαίνεται..

όταν έχω χρόνο και το προχωρίσω θα βάλλω και σχόλια στον κώδικα και θα τον ξαναβάλω εδώ..

Αν μπορέσεις να ανεβάσεις κάπου το εκτελέσιμο για τα windows να το δοκιμάσω και γω θα μου έκανες μεγάλη χάρη..!

Δημοσ.

To εκτελέσιμο για Windows να το βάλω, να το.

Yπάρχει όμως ένα πρόβλημα.

Επειδή το πρωτογενές building & linking των βιβλιοθηκών της Qt ήταν χρονοβόρο και μπελάς (έχω και παλιό μηχάνημα ξέρεις)

την εγκατέστησα χρησιμοποιώντας τα έτοιμα binary αρχεία και τον Installer, δηλ. δεν έχω κάνει εγώ build & link τις βιβλιοθήκες της.

Στην περίπτωση αυτή δεν μπορεί να παραχθεί exe με static linking.

Συνεπώς το exe που παράγω δεν τρέχει αυτόνομα αλλά χρειάζεται και τα dll αρχεία της Qt.

 

Πρέπει να το δοκιμάσεις σε Windows που είναι εγκατεστημένη η Qt, δυστυχώς....

reflect_rays.zip

  • 3 εβδομάδες αργότερα...
Δημοσ.

Εδώ και κάτι μέρες έχω αρχίσει να σκέφτομαι πώς θα το κάνω το κόλπο με διανύσματα (QLineF).. ένα πρόβλημα αρχικά που αντιμετωπίζω είναι πώς θα υπολογίσω το σημείο που θα προσκρούει η ακτίνα..

έχω ένα σημείο που είναι το σημείο εκκίνησης της ακτίνας και ένα δεύτερο που είναι το σημείο που βρίσκεται το ποντίκι κάθε στιγμή..

Αν υποθέσουμε ότι για αρχή έχουμε σαν τοίχους τις τέσσερις πλευρές του παραθύρου μας και θέλουμε να δούμε που θα πέφτει η ακτίνα και σε ποιον τοίχο..

υπάρχει μιά συνάρτηση ( intersect() ) που υπολογίζει ΑΝ ένα διάνυσμα τέμνεται με ένα άλλο, σε ποιο σημείο και αν η τομή είναι στο μέρος του διανύσματος που ορίζεται από τα δύο σημεία ή στην προέκτασή του προς κάποια μεριά..

 

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

καμιά έξυπνη ιδέα από τους ειδικούς..?

Δημοσ.

Κοίτα, απλή γεωμετρία είναι.

 

Θα χειριστείς την ευθεία ως διάνυσμα κι' όχι με την αλγεβρική εξίσωση.

Θυμίσου ότι το B-A είναι το διάνυσμα ΑΒ.

Αν A(x1,y1) είναι το πρώτο σημείο (αρχή) και Β(x2,y2) είναι ένα δεύτερο σημείο, η ευθεία που ορίζουν γράφεται σε παραμετρική μορφή :

r(t)= A+ t (B-A). Το t είναι μια παράμετρος και μπορεί να παίρνει οποιαδήποτε τιμή. Έτσι έχεις ορίσει μια διανυσματική ακτίνα.

Για t>0, το πέρας του r κινείται προς τα "εμπρός" και μάλιστα για t>1 είναι "μετά" από το B.

Για t<0 είναι προς τα "πίσω", δηλ. πίσω από το Α.

Προφανώς είναι r (0)= A και r (1)= Β.

Στην περίπτωσή σου, το "πίσω" θα αντιστοιχεί σε t<0 και άρα το σημείο με t<0 απορρίπτεται...

 

Όλα τα διανύσματα πρέπει να αναπαρίστανται καταρχήν με τις παραμετρικές εξισώσεις και με αυτές να προσδιορίζονται οι τομές,

δηλ. βρίσκοντας την (ή τις) παράμετρο t, ΟΧΙ με αλγεβρικές εξισώσεις.

(Θυμάσαι, την πρώτη φορά που συζητούσαμε έδωσα τον τύπο στης ανάκλασης διανυσματικά...)

 

Το πρόβλημα που έχεις είναι ένα απλό intersection test.

Επειδή εδώ πρόκειται μόνον για το επίπεδο είναι απλά τα πράγματα.

Μια συνάρτηση που να κάνει αυτό που ζητάς (2D test intersection δύο τμημάτων AB, CD) είναι

η παρακάτω (quick & dirty έτσι ; είναι περασμένη η ώρα...)

 

Επιγραμματικά κάνει τα εξής :

α) βρίσκει το σημείο τομής Ε των ευθειών που ορίζουν τα τμήματα

β) επιβεβαιώνει ότι το E βρίσκεται στο λεγόμενο bounding box καθενός από τα AB και CD

 

>// Returns 2 times the signed triangle area. The result is positive if
// abc is ccw, negative if abc is cw, zero if abc is degenerate.
float Signed2DTriArea(Point a, Point b, Point c)
{  return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);  }


// Test if segments ab and cd overlap. If they do, compute and return
// intersection t value along ab and intersection position p
int Test2DSegmentSegment(Point a, Point b, Point c, Point d, float &t, Point &p)
{
float a1 = Signed2DTriArea(a, b, d); 
float a2 = Signed2DTriArea(a, b, c); 

if (a1 * a2 < 0.0f) 
{
   float a3 = Signed2DTriArea(c, d, a); 
   float a4 = a3 + a2 - a1;

   if (a3 * a4 < 0.0f) 
   {
       t = a3 / (a3 - a4);
       p = a + t * (b - a);
       return 1;
   }
}
// Segments not intersecting (or collinear)
return 0;

}

Τα σημεία αναπαρίστανται με μια class ο ορισμός και χρήση της οποίας είναι προφανής.

 

Επίσης, αφορά τμήματα που ΔΕΝ είναι παράλληλα.

Για το αν επικαλύπτονται συγγραμμικά τμήματα πρέπει να γίνει ξεχωριστός έλεγχος.

 

Τέλος, σου επισημαίνω ότι το παραπάνω test intersection αφορά ευθύγραμμα τμήματα (δηλ. με πεπερασμένο μήκος) κι' όχι ευθείες.

Εσύ χρειάζεται να ελέγχεις ένα ευθύγραμμο τμήμα, έστω CD, έναντι μιας ημιευθείας (διανυσματικής ακτίνας) r(t).

To CD είναι ο τοίχος (ξέρεις τα C και D). Το r (t) είναι η διαν. ακτίνα που ορίζουν δύο σημεία Α,Β με το ποντίκι.

Για να χρησιμοποιήσεις την ρουτίνα στην περίπτωση αυτή, κάνε το εξής.

Με τα A,B γνωστά, δώσε αρχικά μια σχετικά μεγάλη τιμή στο t που να καλύπτει την οθόνη σε κάθε περίπτωση, π.χ. to=4000, και βρες ένα καινούριο σημείο B'.

Δηλ. Β' = r(to) = A+ to (B-A).

Προφανώς έτσι θα οριστεί ένα τμήμα AΒ' μεγάλου μήκους που θα προσεγγίζει την ημιευεθεία.

Αντικαθιστάς τώρα το r χρησιμοποιώντας το B' αντί του Β, δηλ. για το AB' έχεις την εξίσωση

r(t) = A+ t (B'-A).

Μπορείς τώρα να χρησιμοποιήσεις το παραπάνω test για το τμήμα αυτό, δηλ. για τα AB' , CD.

 

Αν το παραπάνω κόλπο με το B' έχει προβλήματα ακρίβειας (λόγω μεγάλης σχετικής διαφοράς στα μεγέθη), ψάξε για ένα 'καθαρό' intesection test ευθείας-τμήματος.

 

-

Δημοσ.
καμιά έξυπνη ιδέα από τους ειδικούς..?

πρέπει να χρησιμοποιείς το συμμετρικό του ποντικού ή του σημείου και να βρίσκεις την τομή της ευθείας -συμμετρικό, αρχικό σημείο- με τον τοίχο-τοίχους

αυτό/ά το/α σημείο/α τομής

είναι πάντα στο τμήμα των "τοίχων" που ορίζουν το "παράθυρο"

 

ευκλείδης:mrgreen:

 

δεν υπάρχει μία ακτίνα, αλλά τέσσερεις

*με σύστημα 2 αγνώστων και 2 εξισώσεων βρίσκεις την τομή

 

.

post-36682-129063129615_thumb.jpg

Δημοσ.

Ευχαριστώ θα τα μελετήσω αύριο γιατί τώρα θέλω μια ώρα να καταλάβω κάθε γραμμή..

Απλά να πω μια σκέψη να μου πείτε αν είναι πολύ βλακεία προγραμματιστικά.. (!)

 

Έχω τη γραμμή από τα σημεία Α(χ1,y1) -> Β(χ2, y2).

Αν το χ2>χ1 και y2>y1 τότε από τα δύο σημεία που έχω σαν πιθανά για το σημείο πρόσκρουσης (το ένα είναι από μπροστά και το άλλο από πίσω κατά τη φορά της ακτίνας) εγώ επιλέγω αυτό που έχει για Γ(χ3,y3) χ3>χ2 ή y3>y2... και έτσι "διαλέγω" το σωστό σημείο..

Δημοσ.

Όχι, δεν είναι σωστός τρόπος αυτός.

Θα μπερδευτείς έτσι. Θα πρέπει να διαλέγεις περιπτώσεις κλπ.

Σχεδόν όλα τα προβλήματα test intersection λύνονται με παραμετρικές εξισώσεις και διανυσματικό φορμαλισμό κι όχι αλγεβρικά.

Το αλγεβρικό βήμα πρέπει να είναι όσο το δυνατόν τελευταίο στην λύση.

 

Κάνε το με την παραμετρική εξίσωση που είναι ξεκάθαρη και δουλεύει εννιαία για όλες τις περιπτώσεις :

σε σχέση με την φορά του AB, το "εμπρός" είναι πάντα t>0 και το "πίσω" είναι πάντα t<0, δεν χρειάζεται τίποτε άλλο...

 

Τέλος, η ρουτίνα που έγραψα, παρόλο που είναι πολύ μικρή δεν είναι εύκολα κατανοητή χωρίς κάποιες εξηγήσεις - να μην τις γράφω τώρα.

Επιβεβαίωσε απλώς ότι λειτουργεί και μην ρωτάς τις λεπτομέρειες.

Είναι απλή στη χρήση :

δίνεις τα 4 σημεία (δηλ. για τα τμήματα AB, CD) και επιστρέφει το σημείο τομής τους P και το t κατά μήκος του AB (αν τέμνονται).

 

-

Δημοσ.

@ V.I.Smirnov : Τα κοίταξα τελικά αυτά που μου έγραψες παραπάνω. Ουσιαστικά αυτό που πετυχαίνουμε είναι να μεγαλώσουμε την ευθεία μας ώστε να τέμνει κάποιο τοίχο και μετά υπολογίζουμε το σημείο τομής, έτσι δεν είναι..?

Από τις έτοιμες συναρτήσεις της Qt (αν κατάλαβα καλά αυτά που λες) μπορούμε να το πετύχουμε αυτό αυξάνοντας το μέγεθος προς το δεύτερο σημείο με την setLength() τόσο ώστε σίγουρα να τέμνει κάποιο τοίχο και μετά με την intersect() να βρίσκαμε το σημείο αυτό.. σωστός τρόπος δεν είναι και αυτός..? απλά ήθελα να τον αποφύγω γιατί το να αυξήσω το μέγεθος μέχρι να φύγει από τα όρια της οθόνης μου φάνηκε λίγο "μπακαλίστικος" τρόπος..! Αλλά μάλλον δεν είναι.

Αν κατάλαβα κάτι λάθος διόρθωσε με..

 

@ gtroza : Δεν σε προσπέρασα απλά αυτό που πρότεινες ένα βήμα πιο μπροστά από εδώ που έχω φτάσει...!! Μόλις φτάσω θα το εξετάσω..!

Δημοσ.
@ gtroza : Δεν σε προσπέρασα απλά αυτό που πρότεινες ένα βήμα πιο μπροστά από εδώ που έχω φτάσει...!! Μόλις φτάσω θα το εξετάσω..!

ως μή "κατανοών" αυτά που γράφει ο V.I.Smirnov

απάντησα ώς "κατανοών" το πρόβλημα στην γεωμετρική του μορφή

 

αν χρησημοποιείς μιά βοηθητική ευθεία που σχηματίζεται απο το συμμετρικό* του αρχικού σημείου και τη θέση του κέρσορα

ή

απο το συμμετρικό του κέρσορα και το σημείο

τότε

η τομή της με τον "τοίχο"

είναι πάντα μέσα στο όριο

και το σημείο αυτό, η τομή δηλαδή,

είναι το σημείο "ανάκλασης"

αν έχεις 4 τοίχους - όπως δείχνω στο σχήμα -

η μικρότερη βοηθητική ευθεία (κίτρινο χώμα γραμμής)

είναι ο πιό μικρός δρόμος ανάκλασης, αν αυτό βοηθάει να βρείς πιά ευθεία θα σχεδιαστεί απο τις τέσσερεις

 

αυτά, άν κατάλαβα καλά

 

στο video που είχα αναρτήσει

έτσι "έλυσα" το πρόβλημα σου, για συντομία μέσα σε άλλο πρόγραμμα όπου είχα υλοποιημένη την συνάρτηση για τομή 2 ευθειών , με σύστημα 2 εξισώσεων 2 αγνώστων, xt, yt

 

gtroza

εδώδιμα, αποικιακά, παντός είδους! :mrgreen:

*ή το συμμετρικό/α του κέρσορα

 

.

Δημοσ.

Κατάλαβα πώς το λύνεις το πρόβλημα αλλά δεν έχω καταφέρει να βρω πως θα σχεδιάσω "προγραμματιστικά" το βοηθητικό συμμετρικό σημείο που λες.. ("ΣΥΜΜΕΤΡΙΚΟ" το έχεις ονομάσει στο σχεδιάγραμμά σου.)

δλδ δεν ξέρω πως θα φτιάξω κάθετη ως προς τον τοίχο γραμμή (η οποία θα είναι διπλάσια από την απόσταση του σημείου από αυτόν ώστε να φτάσω στο συμμετρικό..)

έχεις καμιά ιδέα..?

Αν ο τοίχος είναι κάθετος ή οριζόντιος όπως τα όρια της οθόνης είναι εύκολο αλλά αν πρόκειται για διαγώνιο τοίχο δεν ξέρω πως θα το κάνω..

 

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

Δημοσ.
δλδ δεν ξέρω πως θα φτιάξω κάθετη ως προς τον τοίχο γραμμή (η οποία θα είναι διπλάσια από την απόσταση του σημείου από αυτόν ώστε να φτάσω στο συμμετρικό..)

έχεις καμιά ιδέα..?

 

κάθετος ως προς μια τυχαία ευθεία

 

η ευθεία έχει κλιση k=(dy2-dy1)/(dx2-dx1) >πρέπει να γίνει έλεγχος και για το 0

η κάθετος έχει αντίστροφη κλίση κ'=(dx2-dx1)(dy2-dy1)

 

απο το σημείο, του οποίου θέλω να βρώ το συμμετρικό, ως προς μιά ευθεία

δημιουργώ μιά ευθεία με μοναδιαίο μήκος και κλίση αντίστροφη της ευθείας

βρίσκω την τομή της καθέτου με την εν λόγω ευθεία

το συμμετρικό έχει συντεταγμένες

χσ = χτομής+(χτομής-χσημείου)

ψσ = ψτομής+(ψτομής-ψσημείου)

 

έτσι τα έλυσα στο gtroza-cad για την mirror

δεν χρησιμοποίησα έτοιμες συναρτήσεις

ίσως υπάρχει πιό "κομψός" τρόπος

θα μας πεί ο Smirnov

 

kalo kouragio ! :mrgreen:

 

http://gtroza-cad-program.blogspot.com/2010/10/mirror.html

 

.

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...