Я хочу записать программу для рисования в стиле Краски MS.
Для рисования вещей на экране, когда пользователь перемещает мышь, я должен ожидать событий перемещения мыши и привлечь экран каждый раз, когда я получаю тот. По-видимому, mose события перемещения не отправляются очень часто, таким образом, я должен интерполировать движение мыши, чертя линию между текущим положением мыши и предыдущим. В псевдокоде это выглядит примерно так:
var positionOld = null
def handleMouseMove(positionNew):
if mouse.button.down:
if positionOld == null:
positionOld = positionNew
screen.draw.line(positionOld,positionNew)
positionOld = positionNew
Теперь мой вопрос: интерполяция с сегментами прямой линии выглядит слишком зубчатой для моего вкуса, можно ли рекомендовать лучший метод интерполяции? Какой метод GIMP или Adobe Photoshop реализуют?
С другой стороны, существует ли способ увеличить частоту событий перемещения мыши, которые я получаю? Платформа GUI, которую я использую, является wxWidgets.
Платформа GUI: wxWidgets.
(Язык программирования: Haskell, но это не важно здесь),
Править: Разъяснение: Я хочу что-то, что выглядит более гладким, чем сегменты прямой линии, см. изображение (первоначальный размер):
EDIT2: код, который я использую, похож на это:
-- create bitmap and derive drawing context
im <- imageCreateSized (sy 800 600)
bitmap <- bitmapCreateFromImage im (-1) -- wxBitmap
dc <- memoryDCCreate -- wxMemoryDC
memoryDCSelectObject dc bitmap
...
-- handle mouse move
onMouse ... sw (MouseLeftDrag posNew _) = do
...
line dc posOld posNew [color := white
, penJoin := JoinRound
, penWidth := 2]
repaint sw -- a wxScrolledWindow
-- handle paint event
onPaint ... = do
...
-- draw bitmap on the wxScrolledWindow
drawBitmap dc_sw bitmap pointZero False []
который мог бы иметь значение. Возможно, мой выбор wx-классов состоит в том, почему я получаю довольно низкую частоту событий перемещения мыши.
Интерполяция движения мыши отрезками линий - это нормально, GIMP тоже так делает, как показывает следующий скриншот, сделанный при очень быстром движении мыши:
Итак, плавность достигается за счет высокой частоты событий движения мыши. WxWidgets может это сделать, как показано в примере кода для связанного вопроса.
Проблема в вашем коде, Генрих. А именно, сначала рисовать в большой битмап, а затем копировать весь битмап на экран - это не дешево! Чтобы оценить, насколько эффективным нужно быть, сравните вашу задачу с видеоиграми: плавная скорость 30 событий перемещения мыши в секунду соответствует 30fps. Копирование двойного буфера - не проблема для современных машин, но WxHaskell, скорее всего, не оптимизирован для видеоигр, поэтому неудивительно, что вы испытываете некоторое дрожание.
Решение состоит в том, чтобы рисовать только столько, сколько необходимо, т.е. только линии, непосредственно на экране, например, как показано в приведенной выше ссылке.
Думаю, вам нужно изучить документацию Device Context для wxWidgets.
У меня есть код, который выглядит примерно так:
//screenArea is a wxStaticBitmap
int startx, starty;
void OnMouseDown(wxMouseEvent& event)
{
screenArea->CaptureMouse();
xstart = event.GetX();
ystart = event.GetY();
event.Skip();
}
void OnMouseMove(wxMouseEvent& event)
{
if(event.Dragging() && event.LeftIsDown())
{
wxClientDC dc(screenArea);
dc.SetPen(*wxBLACK_PEN);
dc.DrawLine(startx, starty, event.GetX(), event.GetY());
}
startx = event.GetX();
starty = event.GetY();
event.Skip();
}
Я знаю, что это C ++, но вы сказали, что этот язык неуместен, поэтому я надеюсь, что он все равно поможет.
Это позволяет мне сделать следующее:
что кажется значительно более плавным, чем в вашем примере.
Вы можете сделать их действительно гладкими, используя сплайны: http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm
Но вам придется отложить рисование каждого сегмента линии до одного кадра позже, чтобы у вас было начало и конечные точки, а также следующая и предыдущая точки, доступные для расчета.