Запись программы для рисования а-ля Краска MS - как интерполировать между мышью, перемещает события?

Я хочу записать программу для рисования в стиле Краски 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, но это не важно здесь),

Править: Разъяснение: Я хочу что-то, что выглядит более гладким, чем сегменты прямой линии, см. изображение (первоначальный размер):

jagged lines drawn between mouse positions

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-классов состоит в том, почему я получаю довольно низкую частоту событий перемещения мыши.

11
задан Glorfindel 4 August 2019 в 05:07
поделиться

3 ответа

Интерполяция движения мыши отрезками линий - это нормально, GIMP тоже так делает, как показывает следующий скриншот, сделанный при очень быстром движении мыши:

GIMP uses line segments, too

Итак, плавность достигается за счет высокой частоты событий движения мыши. WxWidgets может это сделать, как показано в примере кода для связанного вопроса.

Проблема в вашем коде, Генрих. А именно, сначала рисовать в большой битмап, а затем копировать весь битмап на экран - это не дешево! Чтобы оценить, насколько эффективным нужно быть, сравните вашу задачу с видеоиграми: плавная скорость 30 событий перемещения мыши в секунду соответствует 30fps. Копирование двойного буфера - не проблема для современных машин, но WxHaskell, скорее всего, не оптимизирован для видеоигр, поэтому неудивительно, что вы испытываете некоторое дрожание.

Решение состоит в том, чтобы рисовать только столько, сколько необходимо, т.е. только линии, непосредственно на экране, например, как показано в приведенной выше ссылке.

1
ответ дан 3 December 2019 в 09:40
поделиться

Думаю, вам нужно изучить документацию 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 ++, но вы сказали, что этот язык неуместен, поэтому я надеюсь, что он все равно поможет.

Это позволяет мне сделать следующее:

alt text

что кажется значительно более плавным, чем в вашем примере.

2
ответ дан 3 December 2019 в 09:40
поделиться

Вы можете сделать их действительно гладкими, используя сплайны: http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm

Но вам придется отложить рисование каждого сегмента линии до одного кадра позже, чтобы у вас было начало и конечные точки, а также следующая и предыдущая точки, доступные для расчета.

2
ответ дан 3 December 2019 в 09:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: