Ho creato un programma che limita il mouse a una determinata regione in base a una bitmap in bianco e nero. Il programma è funzionale al 100% così com'è, ma utilizza un algoritmo inaccurato, anche se veloce, per riposizionare il mouse quando si allontana dall'area.
Attualmente, quando il mouse si sposta fuori dall'area, in pratica ciò che accade è questo:
- Viene tracciata una linea tra un punto statico predefinito all'interno della regione e la nuova posizione del mouse.
- Viene trovato il punto in cui quella linea interseca il bordo dell'area consentita.
- Il mouse viene spostato a quel punto.
Funziona, ma funziona perfettamente solo per un cerchio perfetto con il punto predefinito impostato nel centro esatto. Sfortunatamente, questo non sarà mai il caso. L'applicazione verrà utilizzata con una varietà di rettangoli e forme amorfe irregolari. Su tali forme, il punto in cui la linea tracciata interseca il bordo di solito non sarà il punto più vicino sulla forma al mouse.
Devo creare un nuovo algoritmo che trovi il punto più vicino alla nuova posizione del mouse sul bordo dell'area consentita. Ho diverse idee a riguardo, ma non sono sicuro della loro validità, in quanto potrebbero avere troppe spese generali.
Anche se non chiedo codice, potrebbe essere utile sapere che sto usando Objective C / Cocoa, sviluppando per OS X, poiché ritengo che il linguaggio utilizzato possa influenzare l'efficienza dei potenziali metodi.
Le mie idee sono:
-
Usare un po 'di trigonometria per le linee di progetto funzionerebbe, ma ciò richiederebbe un qualche tipo di algoritmo intenso per testare ogni punto su ogni linea fino a trovare il bordo della regione ... ci potrebbero essere qualcosa come 200 linee che dovrebbero avere ciascuna di avere 200 pixel controllati per il nero / bianco ....
-
Usare qualcosa come un algoritmo di pathway A * per trovare il percorso più breve per un pixel nero; tuttavia, A * sembra un uso intensivo delle risorse, anche se probabilmente potrei limitarlo a controllare solo approssimativamente in una direzione. Sembra anche che ci vorrà più tempo e impegno di quello che ho a disposizione per spendere in questa piccola parte del progetto molto più ampio su cui sto lavorando, correggimi se ho torto e non sarebbe una quantità significativa di codice (> 100 linee o circa là).
-
Mappatura del bordo della regione prima che l'applicazione inizi a eseguire il ciclo di tocco dell'evento. Penso che potrei realizzare questo usando il mio attuale algoritmo basato sulla linea per trovare un edge point e quindi avviare un algoritmo che controlla tutti gli 8 pixel attorno a quel pixel, trova il prossimo pixel di bordo in una direzione, e continua a farlo finché non arriva torna al pixel iniziale. Potrei quindi archiviare i dati in una matrice da utilizzare per l'intera durata del programma e il metodo di riposizionamento del mouse controlla la matrice per il pixel più vicino sul bordo alla posizione di destinazione del mouse.
L'ultimo metodo presumibilmente eseguirà la sua mappatura di confine iniziale abbastanza rapidamente. (Dovrebbe solo mappare tra i 2.000 e gli 8.000 pixel, il che significa da 8.000 a 64.000 controllati, e potrei anche memorizzare i dati in modo permanente per rendere l'avvio più veloce.) Tuttavia, sono incerto su quanto sovraccarico ci vorrebbe per scansionare quella matrice per la distanza più breve per ogni singolo evento di spostamento del mouse ... Suppongo che ci possa essere una scorciatoia per limitare il numero di elementi dell'array che verrà controllato a un numero variabile a partire dall'intersezione puntare sulla linea (dal mio algoritmo originale) e alzare / abbassare quel numero per sperimentare il compromesso di sovraccarico / accuratezza.
Per favore fatemi sapere se sto pensando troppo a questo e c'è un modo più semplice che funzionerà bene, o quale di questi metodi sarebbe in grado di eseguire qualcosa come 30 volte al secondo per mantenere il movimento del mouse liscio, o se hai un metodo migliore / più veloce.
Ho postato parti rilevanti del mio codice qui sotto per riferimento e ho incluso un esempio di come potrebbe essere l'area. (Controllo il valore del colore rispetto a una bitmap caricata che è in bianco e nero.)
//
// This part of my code runs every single time the mouse moves.
//
CGPoint point = CGEventGetLocation(event);
float tX = point.x;
float tY = point.y;
if( is_in_area(tX,tY, mouse_mask)){
// target is inside O.K. area, do nothing
}else{
CGPoint target;
//point inside restricted region:
float iX = 600; // inside x
float iY = 500; // inside y
// delta to midpoint between iX,iY and tX,tY
float dX;
float dY;
float accuracy = .5; //accuracy to loop until reached
do {
dX = (tX-iX)/2;
dY = (tY-iY)/2;
if(is_in_area((tX-dX),(tY-dY),mouse_mask)){
iX += dX;
iY += dY;
} else {
tX -= dX;
tY -= dY;
}
} while (abs(dX)>accuracy || abs(dY)>accuracy);
target = CGPointMake(roundf(tX), roundf(tY));
CGDisplayMoveCursorToPoint(CGMainDisplayID(),target);
}
Ecco "is_in_area (int x, int y)":
bool
is_in_area(NSInteger x, NSInteger y, NSBitmapImageRep *mouse_mask){
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSUInteger pixel[4];
[mouse_mask getPixel:pixel atX:x y:y];
if(pixel[0]!= 0){
[pool release];
return false;
}
[pool release];
return true;
}