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

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


karabouzouk...

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

Δεν έχω ασχοληθεί πολύ με το Qt πέρα από τα βασικά αρχικά προγραμματάκια εξοικείωσης..

 

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

 

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

Γενικά θα υπάρχει ένα σημείο (μαύρη τελεία) που θα ορίζω εγώ τη θέση του και από κει θα ξεκινάει η γραμμή, η οποία θα περνάει από τη θέση του κέρσορα του ποντικιού (βελάκι), στη συνέχεια θα καταλήγει σε ένα όριο που πάλι θα ορίζω εγώ τη θέση του (μαύρη κάθετη γραμμή), και τέλος θα συνεχίζει την πορεία της κάνοντας κάτι σαν ανάκλαση στο όριο που έχω θέσει.. (άρα πρέπει a=B).

 

1. ως φόντο πρέπει να φαίνεται η επιφάνεια εργασίας και γενικότερα όλα τα προγράμματα που είναι ανοιχτά από πίσω, ενώ από το πρόγραμμα να φαίνονται μόνο τα κύρια στοιχεία του (μόνο οι γραμμές).

 

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

 

3. αν φτάσω/ φτάσουμε μέχρι εδώ πιστεύω ο ορισμός των παραμέτρων και ένα υποτυπώδες μενού για αλλαγή των παραμέτρων καθώς εκτελείται το πρόγραμμα θα είναι το εύκολο μέρος..

 

Ευχαριστώ εκ των προτέρων..

post-69920-129063124027_thumb.jpg

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 73
  • Δημ.
  • Τελ. απάντηση

Δεν ξέρω για ποιούς λόγους θέλεις να φτιάξεις κάτι τέτοιο αλλά αν το κάνεις για να μάθεις την Qt είσαι σε λάθος δρόμο.

 

Αυτό που ζητάς είναι συνδυασμός μιας πληθώρας πραγμάτων. Πολύ χονδρικά:

- έλεγχο και απόκριση του ποντικιού

- κατασκευή μενού και παραθύρων

- κλάσεις σχεδίασης και παρελκόμενά τους που μπορεί να χρειαστούν

- αποθήκευση δεδομένων αν θέλεις να σώζεται η εικόνα

κ.α.

 

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

Αν τα ξέρεις, Ok πάσσο.

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

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

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

Από κλάσεις γνωρίζω κάποια πράγματα, έχω ασχοληθεί με C++ ξεχωριστά πριν το Qt..

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

Για την θέση του ποντικιού κάθε φορά νομίζω η QCursor είναι η κατάλληλη κλάση.

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

Ευχαριστώ για την απάντηση

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

δεν έχω ασχοληθεί με κάτι τέτοιο.. αν δεν βγάλω άκρη με το Qt ίσως το μελετήσω..!

 

είναι πολύ εύκολο

δεν είμαι προγραμματιστής ! :mrgreen:

φαντάζομαι οτι ξέρεις πως λύνεται γεωμετρικά το πρόβλημά σου

 

 

.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ενδιαφέρον θέμα - ερώτημα..

 

Σε γενικές γραμμές (αν έχω πιάσει τι θες..) αυτό που ζητάς μπορεί να γίνει κατά αυτό τον τρόπο σε C++ Builder χρησιμοποιώντας το framework οπτικού προγραμματισμού VCL.

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

Σε QT, καθώς δεν ασχολούμαι εντατικά μαζί του, δεν μπορώ να σε καθοδηγήσω αν και υπάρχουν κάποιες αναλογίες στην φιλοσοφία του κώδικα που ακολουθεί μεταξύ των δυο frameworks.

 

Το πρόγραμμα προϋποθέτει ότι υπάρχει δηλωμένο ένα TPaintBox component στην φόρμα ως PaintBox1, ενώ ως TransparentColorValue στον Object Inspector έχει δηλωθεί το χρώμα "clFuchsia" το οποίο θα αποτελέσει την μάσκα για την διαφάνεια της φόρμας μας όταν ζητηθεί οπότε τα Windows θα επιτρέπουν την διάδραση του χρήστη με το διάφανο πλέον background. Όμως προσοχή, αν θες να αντιμετωπίσεις ως διάφανα και τα σχήματα που σχεδιάζονται, τουλάχιστον σε VCL, τα πράγματα δυσκολεύουν!

 

>
//-Transparency Draw (c) Directx---------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
TPoint DotPos, LinePosA, LinePosB, RayPosA, RayPosB, MirPosA, MirPosB;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
static UnicodeString strInfo =
	(UnicodeString)
       "PRESS LEFT MOUSE BUTTON SET DOT POSITION\n" +
	"PRESS T TO TOGGLE TRANSPARENCY ON OR OFF\n" +
	"PRESS B TO TOGGLE FORM BORDER ON OR OFF";

// Set Line begin offset.
LinePosA = ScreenToClient(Mouse->CursorPos);
// Set Line end offset (height = 100 pixels).
LinePosB = TPoint(LinePosA.x, LinePosA.y + 100);

// Render Dot..
TCanvas *ptrGr = PaintBox1->Canvas;
// Erase background
ptrGr->Brush->Color = clFuchsia;
ptrGr->FillRect(ClientRect);
// Draw Help
   ptrGr->Font->Color = clYellow;
DrawTextW(PaintBox1->Canvas->Handle, strInfo.w_str(), strInfo.Length(),
	&ClientRect, DT_CENTER);
// Draw Dot
ptrGr->Brush->Color = clRed;
ptrGr->Pen->Color = clRed;
ptrGr->Ellipse(TRect(DotPos.x, DotPos.y, DotPos.x + 30, DotPos.y + 30));
// Draw Line
ptrGr->Pen->Color = clLime;
ptrGr->MoveTo(LinePosA.x, LinePosA.y);
ptrGr->LineTo(LinePosB.x, LinePosB.y);
// Calculate Ray
int CY = (LinePosA.y > LinePosB.y ?
	(LinePosA.y - LinePosB.y) :
	(LinePosB.y - LinePosA.y)) /2;
//Caption = CY;
RayPosA = TPoint(DotPos.x + 15, DotPos.y + 15);
RayPosB = TPoint(LinePosA.x, CY + LinePosA.y);
// Draw Ray
   ptrGr->Pen->Color = clBlue;
ptrGr->MoveTo(RayPosA.x, RayPosA.y);
ptrGr->LineTo(RayPosB.x, RayPosB.y);
// Calculate Mirror Ray
MirPosA = RayPosB;
MirPosB = RayPosA;
MirPosB.y += 90;
// Draw Mirror Ray
   ptrGr->Pen->Color = clSilver;
ptrGr->MoveTo(MirPosA.x, MirPosA.y);
ptrGr->LineTo(MirPosB.x, MirPosB.y);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
	  int X, int Y)
{
// Object placement
switch(Button)
{
	case mbLeft:
		// Set dot position on the center (-15) of the arrow position.
		DotPos = TPoint(X - 15, Y - 15);
		break;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)

{
switch(Key)
{
	case 'T':	// Switch transparency on or off.
		TransparentColor = !TransparentColor;
		break;
	case 'B':	// Switch form border on or off.
		BorderStyle = BorderStyle == bsNone? bsSingle: bsNone;
           Refresh();
		break;
}
}
//---------------------------------------------------------------------------

 

Ακολουθεί βίντεο για το πως τρέχει η παραπάνω υλοποίηση, ώστε να μην χάσεις τον χρόνο σου τζάμπα αν δεν σε ενδιαφέρει:

[ame=http://www.youtube.com/watch?v=AHJjTucrJaY]βίντεο[/ame]

 

Υ.Γ.

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

 

Καλή τύχη!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Σ' ευχαριστώ πολύ DirectX για τον κόπο και τον χρόνο σου..

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

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

όπως και να έχει ο κώδικας σου είναι χρήσιμος σαν βοήθεια για τους υπολογισμούς των ακτίνων και το σχεδιασμό τους που όσο να ναι αν επιλέξω το Qt δεν θα απέχουν πολύ.

 

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

 

Επίσης κάτι που ξέχασα να πω είναι ότι δουλεύω σε Linux ubuntu αν αυτό παίζει κάποιο ρόλο για το VCL.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Χμ.. αυτό ήταν tricky καθώς πρέπει να ανιχνεύσουμε αν η γραμμή της ακτίνας μας (Ray) που φεύγει από τον κύκλο (Dot) μας διασταυρώνεται οπουδήποτε με την γραμμή του τοίχου μας (Line/Wall), οπότε εδώ χρειάζεται ένας αλγόριθμος Line-Intersection ο οποίος μάλιστα θα επιστρέφει όχι μόνο το εάν οι γραμμές διασταυρώνονται (τέμνονται) αλλά και σε πιο σημείο ώστε να πετύχουμε μια ρεαλιστική αντανάκλαση.

 

Με λίγο ψάξιμο βρήκα μια ρουτίνα που κάνει αυτή την εργασία. Πρόκειται για την get_line_intersection γραμμένη από τον Andre LeMothe και δημοσιευμένη στο βιβλίο του «Tricks of the Windows Game Programming Gurus» την οποία μετέτρεψα σε 3 σημεία ώστε να με εξυπηρετεί καλύτερα στην εισαγωγή των παραμέτρων με βάση τους τύπους του C++ Builder.

 

Τέλος, η ρουτίνα υπό συνθήκες παρουσιάζει εξαιρέσεις τύπου «NaN» οπότε για να ξεμπερδεύω μαζί τους μια και καλή, απενεργοποίησα το raise τους από την FPU χρησιμοποιώντας την εντολή “ _control87(MCW_EM, MCW_EM);” του C++ Builder compiler.

 

Σε κάθε περίπτωση, και με οποιοδήποτε framework (Qt ή VCL) ο εντοπισμός της διασταύρωσης των γραμμών είναι το βασικότερο κομμάτι του προγράμματος.

 

Ακολουθεί ο αναθεωρημένος κώδικας:

 

>
//-Transparency Draw (c) Directx---------------------------------------------

#include <vcl.h>
#include <float.h>
#pragma hdrstop

#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
TPoint DotPos, LinePosA, LinePosB, RayPosA, RayPosB, MirPosA, MirPosB;
//---------------------------------------------------------------------------
bool get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
float p2_x, float p2_y, float p3_x, float p3_y, long &i_x, long &i_y)
{
/*
 * Written by Andre LeMothe.
 *
 * !My adaptation, changes:
 *  1. Returns false if any of the input parameters is zero.
 *	2. Changes "float *i_x and *i_y" with equivalent "long&".
 *  3. Returns bool instead of char.
 */
if(!p0_x || !p0_y || !p1_x || !p1_y ||
   !p2_x || !p2_y || !p3_x || !p3_y)
	return false;

float s1_x, s1_y, s2_x, s2_y;
s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

float s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
	// Collision detected
	if (i_x != NULL)
		i_x = p0_x + (t * s1_x);
	if (i_y != NULL)
		i_y = p0_y + (t * s1_y);
	return true;
}

return false; // No collision
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
/*
 * Tip C++ Builder compiler to mask (hide) float-point exceptions
 * (specially the NaN one).
 */
_control87(MCW_EM, MCW_EM);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
static UnicodeString strInfo =
	(UnicodeString)
	"PRESS RIGHT MOUSE BUTTON TO SET WALL POSITION\n" +
	"PRESS LEFT MOUSE BUTTON TO SET DOT POSITION\n" +
	"PRESS T TO TOGGLE TRANSPARENCY ON OR OFF\n" +
	"PRESS B TO TOGGLE FORM BORDER ON OR OFF";

TPoint MP = ScreenToClient(Mouse->CursorPos);
// Render Dot..
TCanvas *ptrGr = PaintBox1->Canvas;
// Erase background
ptrGr->Brush->Color = clFuchsia;
ptrGr->FillRect(ClientRect);
// Draw Help
ptrGr->Font->Color = clYellow;
DrawTextW(PaintBox1->Canvas->Handle, strInfo.w_str(), strInfo.Length(),
	&ClientRect, DT_CENTER);
// Draw Dot
ptrGr->Brush->Color = clRed;
ptrGr->Pen->Color = clRed;
ptrGr->Ellipse(TRect(DotPos.x, DotPos.y, DotPos.x + 30, DotPos.y + 30));
// Draw Line
ptrGr->Pen->Color = clLime;
ptrGr->MoveTo(LinePosA.x, LinePosA.y);
ptrGr->LineTo(LinePosB.x, LinePosB.y);
// Calculate Ray
RayPosA = TPoint(DotPos.x + 15, DotPos.y + 15);
RayPosB = TPoint(MP.x, MP.y);
// Reflect Ray only when intersects with Line (wall)
bool Reflect = get_line_intersection(
	RayPosA.x, RayPosA.y, RayPosB.x, RayPosB.y,
	LinePosA.x, LinePosA.y, LinePosB.x, LinePosB.y,
	RayPosB.x, RayPosB.y);
// Draw Ray
ptrGr->Pen->Color = clBlue;
ptrGr->MoveTo(RayPosA.x, RayPosA.y);
ptrGr->LineTo(RayPosB.x, RayPosB.y);
// Should I reflect Ray?
if(Reflect)
{
	// Calculate Mirror Ray
	MirPosA = RayPosB;
	MirPosB = RayPosA;
	MirPosB.y += 90;
	// Draw Mirror Ray
	ptrGr->Pen->Color = clLime;
	ptrGr->MoveTo(MirPosA.x, MirPosA.y);
	ptrGr->LineTo(MirPosB.x, MirPosB.y);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
	  int X, int Y)
{
// Object placement
switch(Button)
{
	case mbRight:
		Timer1->Enabled = false;
		// Set Line begin offset.
		LinePosA = TPoint(X, Y);
		// Set Line end offset (height = 100 pixels).
		LinePosB = TPoint(LinePosA.x, LinePosA.y + 100);
		Timer1->Enabled = true;
		break;
	case mbLeft:
		// Set dot position on the center (-15) of the arrow position.
		Timer1->Enabled = false;
		DotPos = TPoint(X - 15, Y - 15);
		Timer1->Enabled = true;
		break;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)

{
switch(Key)
{
	case 'T':	// Switch transparency on or off.
		TransparentColor = !TransparentColor;
		break;
	case 'B':	// Switch form border on or off.
		BorderStyle = BorderStyle == bsNone? bsSingle: bsNone;
           Refresh();
		break;
}
}
//---------------------------------------------------------------------------

 

Και ένα βίντεο για το πώς λειτουργεί:

[ame=http://www.youtube.com/watch?v=LreJt9KaY-Q]βίντεο[/ame]

Επίσης κάτι που ξέχασα να πω είναι ότι δουλεύω σε Linux ubuntu αν αυτό παίζει κάποιο ρόλο για το VCL.

Δυστυχώς πρόκειται για εργαλείο προγραμματισμού μόνο για MS-Windows - πριν πολλά χρόνια έγινε μια προσπάθεια να μεταφερθεί σε Linux με την επωνυμία CLX (αλλού γνωστό ως Kylix) αλλά δεν τελεσφόρησε.

 

Καλή συνέχεια!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Να σαι καλά και ευχαριστώ για τον κόπο που έκανες..

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

Ο ρόλος του κέρσορα κατά κάποιον τρόπο είναι να κατευθύνει την ακτίνα και όχι η ακτίνα να σταματάει εκεί που είναι ο κέρσορας. Πρέπει να συνεχίζει περνώντας από τον κέρσορα συνεχίζοντας προς τον τοίχο και στη συνέχεια να ανακλάται. Ενώ εδώ όταν ο κέρσορας είναι πρίν τον τοίχο η ακτίνα σταματά στο σημείο του κέρσορα και δεν συνεχίζει την πορεία της.

 

Αν έχει κάποιος καμιά συμβουλή για το Qt ας την πει ακόμα και για κάποιο συγκεκριμένο μέρος του προγράμματος.

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

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Έτσι για την ιστορία:

 

Ο κώδικας περιστρέφει προς τα επάνω την ακτίνα (Ray) γύρο από το Dot όταν ο χρήστης μετακινεί προς τα επάνω την μεσαία ροδέλα του mouse ενώ πράττει αντίστροφα όταν την μετακινεί προς τα κάτω:

 

>
//-Transparency Draw (c) Directx---------------------------------------------

#include <vcl.h>
#include <float.h>
#pragma hdrstop

#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
TPoint DotPos, LinePosA, LinePosB, RayPosA, RayPosB, MirPosA, MirPosB;
double Angle = 0;
//---------------------------------------------------------------------------
bool get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
float p2_x, float p2_y, float p3_x, float p3_y, long &i_x, long &i_y)
{
/*
 * Written by Andre LeMothe.
 *
 * !My adaption changes:
 *  1. Returns false if any of the input parameters is zero.
 *	2. Changes "float *i_x and *i_y" with equivalent "long&".
 *  3. Returns bool instead of char.
 */
if(!p0_x || !p0_y || !p1_x || !p1_y ||
   !p2_x || !p2_y || !p3_x || !p3_y)
	return false;

float s1_x, s1_y, s2_x, s2_y;
s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

float s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
	// Collision detected
	if (i_x != NULL)
		i_x = p0_x + (t * s1_x);
	if (i_y != NULL)
		i_y = p0_y + (t * s1_y);
	return true;
}

return false; // No collision
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
/*
 * Tip C++ Builder compiler to mask (hide) float-point exceptions
 * (specially the NaN one).
 */
_control87(MCW_EM, MCW_EM);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
static UnicodeString strInfo =
	(UnicodeString)
	"ROTATE BEAM USING MOUSE SCROLL WHEEL\n" +
	"PRESS RIGHT MOUSE BUTTON TO SET WALL POSITION\n" +
	"PRESS LEFT MOUSE BUTTON TO SET DOT POSITION\n" +
	"PRESS T TO TOGGLE TRANSPARENCY ON OR OFF\n" +
	"PRESS B TO TOGGLE FORM BORDER ON OR OFF";

TPoint MP = ScreenToClient(Mouse->CursorPos);
// Render Dot..
TCanvas *ptrGr = PaintBox1->Canvas;
// Erase background
ptrGr->Brush->Color = clFuchsia;
ptrGr->FillRect(ClientRect);
// Draw Help
ptrGr->Font->Color = clYellow;
DrawTextW(PaintBox1->Canvas->Handle, strInfo.w_str(), strInfo.Length(),
	&ClientRect, DT_CENTER);
// Draw Dot
ptrGr->Brush->Color = clRed;
ptrGr->Pen->Color = clRed;
ptrGr->Ellipse(TRect(DotPos.x, DotPos.y, DotPos.x + 30, DotPos.y + 30));
// Draw Line
ptrGr->Pen->Color = clLime;
ptrGr->MoveTo(LinePosA.x, LinePosA.y);
ptrGr->LineTo(LinePosB.x, LinePosB.y);
// Calculate Ray
RayPosA = TPoint(DotPos.x + 15, DotPos.y + 15);
// Ray rotation
int RY = ClientRect.Width() * Cos(Angle * 0.017453292),
	RX = ClientRect.Width() * Sin(Angle * 0.017453292);
RayPosB = TPoint(RX + DotPos.x, RY + DotPos.y);
// Reflect Ray only when intersects with Line (wall)
bool Reflect = get_line_intersection(
	RayPosA.x, RayPosA.y, RayPosB.x, RayPosB.y,
	LinePosA.x, LinePosA.y, LinePosB.x, LinePosB.y,
	RayPosB.x, RayPosB.y);
// Draw Ray
ptrGr->Pen->Color = clBlue;
ptrGr->MoveTo(RayPosA.x, RayPosA.y);
ptrGr->LineTo(RayPosB.x, RayPosB.y);
// Should I reflect Ray?
if(Reflect)
{
	// Calculate Mirror Ray
	MirPosA = RayPosB;
	MirPosB = RayPosA;
	MirPosB.y = ClientRect.Height() + 90;
	// Draw Mirror Ray
	ptrGr->Pen->Color = clLime;
	ptrGr->MoveTo(MirPosA.x, MirPosA.y);
	ptrGr->LineTo(MirPosB.x, MirPosB.y);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
	  int X, int Y)
{
// Object placement
switch(Button)
{
	case mbRight:
		Timer1->Enabled = false;
		// Set Line begin offset.
		LinePosA = TPoint(X, Y);
		// Set Line end offset (height = 100 pixels).
		LinePosB = TPoint(LinePosA.x, LinePosA.y + 100);
		Timer1->Enabled = true;
		break;
	case mbLeft:
		// Set dot position on the center (-15) of the arrow position.
		Timer1->Enabled = false;
		DotPos = TPoint(X - 15, Y - 15);
		Timer1->Enabled = true;
		break;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)

{
switch(Key)
{
	case 'T':	// Switch transparency on or off.
		TransparentColor = !TransparentColor;
		break;
	case 'B':	// Switch form border on or off.
		BorderStyle = BorderStyle == bsNone? bsSingle: bsNone;
           Refresh();
		break;
}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos,
         bool &Handled)
{
// Rotate ray anti-clockwise
Angle += 0.50;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift, TPoint &MousePos,
	  bool &Handled)
{
// Rotate ray clockwise
Angle -= 0.50;
}
//---------------------------------------------------------------------------

 

Ενώ η φορά της αλλάζει, το μέγεθος της μένει σταθερό.

 

Το τελικό βίντεο:

[ame=http://www.youtube.com/watch?v=OSt_XuZFNkA]βίντεο[/ame]

:)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

με βάση την κάθετο

βρίσκεται το συμμετρικό της θέσης του κέρσορα

βρίσκεται το σημείο τομής της ευθείας -αρχικό σημείο, συμμετρικό σημείο- η ευθεία σχεδιάζεται με το χρώμα του background

 

τέλος ορίζεται η polyline -αρχικό σημείο, σημείο τομής, θέση κέρσορα-

 

η polyline αυτή "ανασχεδιάζεται" συνεχώς με την κίνηση του ποντικιού

 

σε tcltk γίνεται "πατκιούτ" ! :mrgreen:

 

.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

με βάση την κάθετο

βρίσκεται το συμμετρικό της θέσης του κέρσορα

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

 

Για το πρόβλημα της ανάκλασης, θυμάμαι μια κομψή λύση με διανυσματικό φορμαλισμό.

Έστω ένα διάνυσμα α που προσπίπτει σε μια ευθεία L και ανακλάται στην διεύθυνση r.

n είναι το μοναδιαίο κάθετο διάνυσμα στην ευθεία L, το ανακλώμενο διάνυσμα r του α δίνεται από την σχέση :

 

r = α - 2( α . n) n

 

Eπειδή στην προκειμένη περίπτωση η ευθεία L (το "όριο" που θέτει ο φίλος) είναι κατακόρυφη,

για το n είναι n={1,0} και η παραπάνω σχέση εφαρμόζεται άμεσα.

 

Π.χ. έστω η L είναι κατακόρυφη και έχει n={1,0}.

α={4,-2} η σχέση δίνει r={-4,-2} όπως αναμένεται. Οι γωνίες πρόσπτωσης και ανάκλασης είναι αμφότερες atan(0.5).

 

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

 

Τέλος, οι νόμοι του Snell συμβατικά λαμβάνουν τις γωνίες μετρούμενες από το κάθετο διάνυσμα n και

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

π/2 - a και π/2 - b. Δεν είναι λάθος όπως το κάνεις αλλά καλύτερα να ακολουθείς την σύμβαση.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

http://gtroza-cad-program.blogspot.com/2010/09/problem.html

δεν είναι τέλειο

αλλά δεν είμαι του "χώρου" !:mrgreen:

 

 

@V.I.Smirnov έλεος ! αρχιτέκτονας είμαι ! :mrgreen::mrgreen::mrgreen:

αλλά σου βγάζω το καπέλο !

και στον Directx φυσικά!

 

.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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


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