Quale di questi algoritmi è il migliore per il mio obiettivo?

4

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:

  1. Viene tracciata una linea tra un punto statico predefinito all'interno della regione e la nuova posizione del mouse.
  2. Viene trovato il punto in cui quella linea interseca il bordo dell'area consentita.
  3. 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;
}

bitmap per

    
posta JonathonG 22.11.2011 - 07:19
fonte

3 risposte

2

Supponendo che tu abbia un modo affidabile per raccogliere un numero discreto di punti (x, y) che descrivono il bordo della tua immagine, proverei a usare una combinazione del tuo primo e del terzo metodo.

In tal caso, questo è un classico esempio di geometria computazionale:

link

Modifica

Poiché uno dei tuoi punti è fisso, potresti persino essere in grado di ridurre il tempo di esecuzione a O (n) semplicemente passando in modo lineare sui punti di confine, calcolando la distanza, ad es. distance = sqrt ((x1-x2) ^ 2 + (y1-y2) ^ 2), e tiene traccia del punto che ha prodotto il minimo.

Forse c'è un modo intelligente per ottimizzare la ricerca sui tuoi punti di confine?

Tutti i metodi analitici che posso immaginare si basano sul fatto che i punti di confine sono rappresentativi di alcune funzioni continue, che non sono necessariamente.

EDIT2

Naturalmente, non dovresti entrare in questo algoritmo di ricerca a meno che la tua routine is_in_area fallisca.

    
risposta data 22.11.2011 - 21:03
fonte
3

Che cosa succede per ricordare l'ultimo punto quando il mouse era all'interno e lanciare raggi a quel punto ma anche ruotati di 1, 2, 4, 8, ... gradi su entrambi i lati? Quindi seleziona il punto più vicino all'intersezione di egde se il risultato è troppo grossolano, puoi ripetere la procedura per "regolarla con precisione", iniziando ora dal punto più vicino trovato, non dall'ultima posizione interna.

    
risposta data 23.11.2011 - 15:27
fonte
1

Ho un'altra idea. Potresti usare una variante del tuo terzo approccio. Mappare il bordo della forma e utilizzare tutti questi punti per calcolare il punto di equilibrio della figura. Una volta che hai il punto di equilibrio puoi facilmente usarlo per creare una linea tra il punto di equilibrio e il punto del mouse per creare una linea. Da questa linea calcoli l'intersezione con la forma.

    
risposta data 23.11.2011 - 20:12
fonte

Leggi altre domande sui tag