Я создал программу, которая ограничивает мышь определенным регионом на основе черно-белого растрового изображения. Программа на 100% функциональна как есть, но использует неточный, хотя и быстрый, алгоритм для изменения положения мыши, когда она выходит за пределы области.
В настоящее время, когда мышь перемещается за пределы области, в основном происходит следующее:
- Линия проводится между предварительно определенной статической точкой внутри области и новой позицией мыши.
- Найдена точка, где эта линия пересекает край разрешенной области.
- Мышь перемещается в эту точку.
Это работает, но работает идеально только для идеального круга с заранее определенной точкой, установленной в точном центре. К сожалению, этого никогда не произойдет. Приложение будет использоваться с различными прямоугольниками и неправильной, аморфной формы. На таких фигурах точка, где нарисованная линия пересекает край, обычно не будет ближайшей точкой на фигуре к мыши.
Мне нужно создать новый алгоритм, который находит ближайшую точку к новой позиции мыши на краю разрешенной области. Как я могу это сделать? Предпочтительно, чтобы метод мог выполняться достаточно быстро, чтобы обеспечить плавное движение мыши при перетаскивании мыши к краю области.
(я делаю это в Objective C / Cocoa на OS X 10.7, однако, псевдокод подойдет, если вы не хотите набирать код или не знаете Objective C / C)
Спасибо!
Вот мой текущий алгоритм:
#import <Cocoa/Cocoa.h>
#import "stuff.h"
#import <CoreMedia/CoreMedia.h>
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;
}
CGEventRef
mouse_filter(CGEventTapProxy proxy, CGEventType type, CGEventRef event, NSBitmapImageRep *mouse_mask) {
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);
}
return event;
}
int
main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
stuff *stuff_doer = [[stuff alloc] init];
NSBitmapImageRep *mouse_mask= [stuff_doer get_mouse_mask];
CFRunLoopSourceRef runLoopSource;
CGEventMask event_mask;
event_mask = CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDragged);
CGSetLocalEventsSuppressionInterval(0);
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, event_mask, mouse_filter, mouse_mask);
if (!eventTap) {
NSLog(@"Couldn't create event tap!");
exit(1);
}
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
CFRelease(eventTap);
CFRelease(runLoopSource);
[pool release];
exit(0);
}
Это пример растрового изображения области, которое можно использовать, черный цвет - это разрешенная область.
Это показывает, почему преобразование в многоугольник не было бы удобным или даже правдоподобным.