От новичка до гуру: Курсы программирования на CyberDuff

Delphi Graphics32 рисует прозрачный эллипс на слое

Я хочу иметь возможность рисовать пустой эллипс на прозрачном слое в ImgView32. Любая идея, как это сделать? Пока все, о чем я могу думать, это:

 BL := TBitmapLayer.Create(ImgView.Layers);
    BL.Bitmap.DrawMode := dmTransparent;
    BL.Bitmap.SetSize(imwidth,imheight);
    BL.Bitmap.Canvas.Pen.Width := penwidth;
    BL.Bitmap.Canvas.Pen.Color := pencolor;
    BL.Location := GR32.FloatRect(0, 0, imwidth, imheight);
    BL.Scaled := False;
    BL.OnMouseDown := LayerMouseDown;
    BL.OnMouseUp := LayerMouseUp;
    BL.OnMouseMove := LayerMouseMove;
    BL.OnPaint := LayerOnPaint;

...
BL.Bitmap.Canvas.Pen.Color := clBlue;
BL.Bitmap.Canvas.MoveTo(FStartPoint.X, FStartPoint.Y);
BL.Bitmap.Canvas.Ellipse(FStartPoint.X, FStartPoint.Y,FEndPoint.X, FEndPoint.Y); 

Начальная и конечная точки получаются в событиях мыши.

На самом деле я пытаюсь нарисовать динамический эллипс (по событиям мыши). Таким образом, задействованы события onMouseDown (LayerMouseDown), onMouseUp (LayerMouseUp) и OnMouseMove (LayerMouseMove). В качестве справки проверьте этот вопрос, он касается динамического рисования линии. Я хочу сделать то же самое, но с эллипсами вместо линий.

Итак, вместо AddLineToLayer у меня есть процедура AddCircleToLayer. Теперь события выглядят так:

procedure TForm5.SwapBuffers32;
begin
    TransparentBlt(
      BL.Bitmap.Canvas.Handle, 0, 0, BL.Bitmap.Width, BL.Bitmap.Height,
      bm32.Canvas.Handle, 0, 0, bm32.Width, bm32.Height, clWhite);
end;

procedure TForm5.ImgViewResize(Sender: TObject);
begin
  OffsX := (ImgView.ClientWidth - imwidth) div 2;
  OffsY := (ImgView.ClientHeight - imheight) div 2;
  BL.Location := GR32.FloatRect(OffsX, OffsY, imwidth+OffsX, imheight+OffsY);
end;

procedure TForm5.LayerMouseDown(Sender: TObject; Buttons: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FStartPoint := Point(X-OffsX, Y-OffsY);
  FDrawingLine := true;
end;

procedure TForm5.LayerMouseMove(Sender: TObject; Shift: TShiftState; X,  Y: Integer);
begin
  if FDrawingLine then
  begin
    SwapBuffers32;
      if RadioGroup1.ItemIndex=0 then
      begin
        BL.Bitmap.Canvas.Pen.Color := pencolor;
        BL.Bitmap.Canvas.MoveTo(FStartPoint.X, FStartPoint.Y);
        BL.Bitmap.Canvas.LineTo(X-OffsX, Y-OffsY);
      end
      else
      begin
        BL.Bitmap.Canvas.Pen.Color := pencolor;
        BL.Bitmap.Canvas.MoveTo(FStartPoint.X, FStartPoint.Y);
        SwapBuffers32;
        BL.Bitmap.Canvas.Ellipse(FStartPoint.X, FStartPoint.Y,X-OffsX, Y-OffsY);
      end;
  end;
end;

procedure TForm5.LayerMouseUp(Sender: TObject; Buttons: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
      if RadioGroup1.ItemIndex=0 then
      begin
        FDrawingLine := false;
        FEndPoint := Point(X-OffsX, Y-OffsY);
        AddLineToLayer;
        SwapBuffers32;
      end
      else
      begin
        FDrawingLine := false;
        FEndPoint := Point(X-OffsX, Y-OffsY);
        AddCircleToLayer;
        SwapBuffers32;
      end
end;

procedure TForm5.LayerOnPaint(Sender: TObject; Buffer: TBitmap32);
begin
  SwapBuffers32;
end;

procedure TForm5.AddLineToLayer;
begin
  bm32.Canvas.Pen.Color := pencolor;
  bm32.Canvas.Pen.Width := penwidth;
  bm32.Canvas.MoveTo(FStartPoint.X, FStartPoint.Y);
  bm32.Canvas.LineTo(FEndPoint.X, FEndPoint.Y);
end;

procedure TForm5.AddCircleToLayer;
begin
  bm32.Canvas.Pen.Color := pencolor;
  bm32.Canvas.Pen.Width := penwidth;
  bm32.Canvas.MoveTo(FStartPoint.X, FStartPoint.Y);
  bm32.Canvas.Ellipse(FStartPoint.X, FStartPoint.Y,FEndPoint.X, FEndPoint.Y);
  SwapBuffers32;
end;

Но когда я использую этот код, круг (эллипс) заполняется белым (как на этом изображении) введите описание изображения  здесь пока я не начну рисовать следующий эллипс (поэтому onMouseMove и onMouseUp эллипс заполняется). И только когда я делаю еще один onMouseDown, тогда предыдущий круг становится пустым, но новый эллипс также заполняется белым (как на этом изображении) введите здесь описание изображения

Также, если вы попытаетесь сделать больше эллипсов один за другим и поверх старых, вы заметите, что будут следы эллипсов onMouseMove, как на этом изображении:

введите здесь описание изображения

Так что должно быть что-то, что мне не хватает в этом коде.

Пожалуйста, помогите мне решить эту проблему.


  • Что ж, на самом деле ответ был довольно прост... установите кисть. Цвет на 0, прежде чем рисовать эллипс... Это делает эллипс пустым. Удивительно просто :) 18.02.2015
  • Установка Brush.Color на 0 фактически сделает его черным. Однако установка Brush.Style на bsClear должна помочь. 18.02.2015
  • Вы пробовали Brush.Style := bsClear? 23.02.2015

Ответы:


1

Если вы используете последний код GR32 из магистрали, вы также можете использовать этот фрагмент кода для определения эллипса.

Points := Ellipse(Center.X, Center.Y, Radius.X, Radius.Y);

или еще проще

Points := Ellipse(Center, Radius);

где Points определяется как

Points: TArrayOfFloatPoint;

Это создает многоугольник эллипса с центром в Center и независимым радиусом, связанным с x и y, определенным Radius.

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

PolygonFS(Bitmap, Points, SomeColor32);

чтобы отобразить заполненный эллипс.

Однако, если вы хотите отображать только кадр, вы можете использовать этот

PolylineFS(Bitmap, Points, AnotherColor32, True, PenWidth);

Параметры для этого

  1. Bitmap = экземпляр TBitmap32 для рендеринга
  2. Точки = точки многоугольника (как определено выше)
  3. AnotherColor32 = цвет, который используется для рендеринга
  4. True = замкнутый многоугольник (иначе ваш эллипс будет иметь зазор между начальной и конечной точкой
  5. PenWidth = Ширина кадра

Если хотите, вы также можете отобразить это за один вызов, например

PolylineFS(Bitmap, Ellipse(Center, Radius), AnotherColor32, True, PenWidth);

Чтобы получить произвольный (повернутый) эллипс, вам необходимо преобразовать многоугольник перед рендерингом. Ты можешь использовать

TransformPolygon(Points, Transformation);

для этого, который получает экземпляр TTransformation в качестве второго параметра. Это может включать в себя все распространенные операции, такие как поворот, наклон, масштабирование и перемещение.

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

Приведенный выше код требует включения в ваш проект модулей GR32_VectorUtils, GR32_Polygons, например

uses
  GR32_VectorUtils, GR32_Polygons;

Преимущество заключается в том, что вы не полагаетесь на GDI для рендеринга, и поэтому вы можете выбрать средство рендеринга из доступных средств рендеринга из GR32. Некоторые из них включают эффект, подобный ClearType, и улучшают видимость на ЖК-экранах. Не говоря уже о качестве сглаживания и возможности управления гаммой для рендеринга.

18.02.2015
  • Ваш вклад всегда ценится CWBudde. Еще раз спасибо за настоящий подход Graphics32. Пожалуйста, уточните немного о выборе доступных рендереров. Например, если я хочу, чтобы кадр был более гладким? Как насчет управления гаммой, сглаживанием и четким типом? Я уверен, что и другие выиграют от этого. 20.02.2015
  • CWBudde, пожалуйста, взгляните и на этот вопрос: обычные слои со слоями рисования">stackoverflow.com/questions/28623999/ . Я мог бы использовать ваш вклад там ... 20.02.2015

  • 2

    Поэтому при рисовании круга/эллипса установите цвет кисти на 0, например:

    procedure TForm5.AddCircleToLayer;
    begin
      bm32.Canvas.Pen.Color := pencolor;
      bm32.Canvas.Pen.Width := penwidth;
      bm32.Canvas.Brush.Color := 0; // this here does the magic
      bm32.Canvas.MoveTo(FStartPoint.X, FStartPoint.Y);
      bm32.Canvas.Ellipse(FStartPoint.X, FStartPoint.Y,FEndPoint.X, FEndPoint.Y);
      SwapBuffers32;
    end;
    

    Также сделайте то же самое в событии LayerMouseMove.

    17.02.2015
    Новые материалы

    Обратное распространение в RNN объяснил
    Пошаговое объяснение вычислительных графов и обратного распространения ошибки в рекуррентной нейронной сети. Введение На заре машинного обучения, когда не было фреймворков, большая часть..

    Используйте Python для анализа рейтингов и обзоров курсов OMSCS Технологического института Джорджии
    Как получать и анализировать рейтинги курсов OMSCS, данные о сложности и рабочей нагрузке и компилировать их в интерактивную информационную панель Программа Онлайн-магистр компьютерных наук..

    Стеки и очереди в Python
    Стеки и очереди в Python Изучите 2 популярные линейные структуры данных. Зачем это читать? Стеки и очереди ( произносится как kyo͞o или kiu ) - это простые, но мощные структуры данных,..

    Matt’s Tidbits #99  — «Элегантная обработка нуля»
    На прошлой неделе я писал о некоторых крайних случаях правдоподобия в JavaScript . На этот раз у меня есть небольшая заметка об элегантной обработке нулевых/неопределенных значений. null..

    Обучение работе с AWS с Habana Gaudi
    Использование возможностей выделенных обучающих чипов DNN — часть 2 В октябре прошлого года AWS объявила о появлении типа инстанса Amazon EC2 DL1 . DL1, оснащенный восемью ускорителями..

    Сортировка вставками с помощью JavaScript
    Простые типы алгоритмов сортировки Пузырьковая сортировка ➝ O(n²) Сортировка вставками ➝ O(n²) Сортировка выбором ➝ O (n²) Сортировка слиянием ➝ O (n * log n) Быстрая сортировка ➝..

    Я попросил ChatGPT решить 5 вопросов по программированию LeetCode
    ChatGPT , диалоговый ИИ от OpenAI , выпущенный в ноябре 2022 года, может понять и ответить практически на все, что вы спросите. У него есть возможность писать стихи, штамповать эссе и писать..