Как создать зеркальную форму на графике

У меня есть список пунктов

List<Point> pointList = new List<Point>();

pointList.Add(new Point(0,0));
pointList.Add(new Point(30,0));
pointList.Add(new Point(30,-100));
pointList.Add(new Point(0,-100));

Затем нарисуйте линию

Pen pen = new Pen(Color.Red,2);

g.Drawline(pen,pointList[0],pointList[1]);

g.Drawline(pen,pointList[3],poin,tList[4]);

для этого я получу результат левого изображения в ссылке

Как создать зеркальную форму на графике

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

есть ли какой-нибудь метод, который может отразить графику, которую я рисую из списка точек?

это там что-то вроде копировать и перевернуть графику и составить?

Спасибо

Я не получил именно то, что вы хотите. вы хотите отразить левое изображение на правом прицеле или правое изображение на правой стороне? это будет резать, поэтому я не понимаю, что вы имеете в виду. вы можете дать нам пример ввода и вывода?

sLw 07.01.2019 09:33

Все API, связанные с GDI, имеют двухмерные преобразования, как и пространство имен System.Drawing. Вы можете использовать Graphics.TransformPoints для преобразования одного массива точек в другой, используя матрицу 2D преобразования

Panagiotis Kanavos 07.01.2019 09:53

Проверьте Использование преобразований в управляемом GDI + и другие статьи в главе, включая контейнеры и диапазоны. Вы можете преобразовать определенные области, элементы управления или объекты Path. OTOH, почему бы не использовать WPF, в котором все эти атрибуты выражены как преобразования прямо в XAML компонента?

Panagiotis Kanavos 07.01.2019 09:56

Это общий вопрос очень. Что ты пытаешься сделать? Помимо API преобразования в Winforms и встроенной поддержки XAML для WPF и более поздних версий, у вас также есть преобразования в пространстве имен System.Numeric.Vectors, когда вы не хотите отображать результаты на экране.

Panagiotis Kanavos 07.01.2019 09:58
Отразить GraphicsPath. В этом примере матрица Mirror применяется к GraphicsPath, но это не обязательно. Прочтите заметки.
Jimi 07.01.2019 14:35

Вы решили свои проблемы?

TaW 07.02.2019 12:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
1 197
3

Ответы 3

С точки зрения API это очень широкий вопрос. Все API, связанные с графикой, имеют преобразования. То же самое и с классами в пространстве имен System.Numerics, которые используются в основном в операциях SIMD. С точки зрения геометрии, ответ очевиден: вам нужно применить правильное преобразование ко всем точкам. В данном конкретном случае это отражение.

Некоторые API-интерфейсы поддерживают отражение напрямую, например Вектор2.:

var points=new[]{
        new Vector2(0,0),
        new Vector2(30,0),
        new Vector2(30,-100),
        new Vector2(0,-100),                                                            
};

var reflect_y=new Vector2(1,0);
var reflected = points.Select(p=>Vector2.Reflect(p,reflect_y))            
                      .ToArray();

Распечатка отраженных точек дает:

0, 0
-30, 0
-30, -100
0, -100

В других случаях можно вычислить матрицу преобразования и умножить на нее каждую точку на:

Reflection Matrix

Этот статья объясняет математику и показывает значения, которые следует использовать для отражения по осям X, Y или по обоим. В этом случае желаемая матрица:

Reflect Y

Преобразования в компьютерной графике применяются как матрицы 3x2, где третий столбец применяет транспонирование по каждой оси. В этом случае мы не хотим перемещать результат, поэтому третий столбец содержит нули.

На этот раз вместо Reflect используется Vector2.Transform:

var reflect_y=new Matrix3x2(-1,0,0,1,0,0);
var reflected = ( from point in points
                  select Vector2.Transform(point,reflect_y)            
                ).ToArray();

В GDI + преобразование представлено объектом Матрица. Отражение недоступно, но его можно заменить на Матрица.Масштаб, когда мы хотим отражать только по осям X или Y. Например :

var m=new Matrix();
m.Scale(1,-1);
m.TransformVectors(points);

Будет отражать массив точек путем умножения всех значений X на 1 и всех значений Y на -1.

Имея GraphicsPath, вы можете использовать следующие методы для зеркалирования пути:

GraphicsPath MirrorLeft(GraphicsPath path)
{
    var r = path.GetBounds();
    var p = (GraphicsPath)path.Clone();
    p.Transform(new Matrix(-1, 0, 0, 1, 2 * r.Left, 0));
    return p;
}
GraphicsPath MirrorRight(GraphicsPath path)
{
    var r = path.GetBounds();
    var p = (GraphicsPath)path.Clone();
    p.Transform(new Matrix(-1, 0, 0, 1, 2 * (r.Left + r.Width), 0));
    return p;
}

MirrorLeft отражает путь, используя левую часть пути в качестве оси, а MirrorRight использует правую сторону пути в качестве оси.

На следующем рисунке красная дуга - оригинал, зеленая - зеркальная левая, а синяя - зеркальная правая:

Вот код для вывода выше:

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    using (var path1 = new GraphicsPath())
    {
        path1.AddArc(new Rectangle(100, 100, 200, 200), -90, 90);
        using (var pen1 = new Pen(Color.Red, 3))
            e.Graphics.DrawPath(pen1, path1);

        using (var path2 = MirrorLeft(path1))
        using (var pen2 = new Pen(Color.Green, 3))
            e.Graphics.DrawPath(pen2, path2);
        using (var path3 = MirrorRight(path1))
        using (var pen3 = new Pen(Color.Blue, 3))
            e.Graphics.DrawPath(pen3, path3);
    }
    base.OnPaint(e);
}

Конечно, это не ваш проблема, но OP никогда не будет рисовать эту форму, используя код, представленный в вопросе, с [Graphics].DrawLine(), неправильной индексацией и отрицательными значениями (если нет активного преобразования в исходной точке). Фигуру можно нарисовать с помощью [Graphics].DrawLines(pen, pointList.ToArray()) или [GraphicsPath].AddLines(pointList.ToArray()), не закрывая фигуру.

Jimi 07.01.2019 17:01

Вы можете просто кувырок объект Графика:

e.Graphics.DrawLines(Pens.Black, pointList.ToArray());
e.Graphics.ScaleTransform(-1, 1);
// you need to know at which x value the flipping axis should be!
e.Graphics.TranslateTransform(..., 0);
e.Graphics.DrawLines(Pens.Red, pointList.ToArray());

Обратите внимание, что вам нужно знать где, которое вы хотите перевернуть (ось зеркала). Для эффекта, который вы показываете, вам нужно двигаться вправо вдвое левее (минимум) левого края рисунка ..:

int xmin = pointList.Min(x => x.X);
int xmax = pointList.Max(x => x.X);

e.Graphics.TranslateTransform(xmin * 2, 0);

Также обратите внимание, что Graphics может отображать только значения положительный, если вы не переместите объект Graphics соответствующим образом. Так что без TranslateTransform ваши числа никогда не будут отображаться. (Я поменял их для демонстрации.)

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

Как отмечает Джими, если вы хотите продолжить рисование, вам нужно будет выполнить либо e.Graphics.ResetTransform(); после переворота, либо, если вы уже подготовили весь рисунок, переведя холст в положительную область, восстановить состояние, в котором он был до переворота. . Для этого сначала сохраните состояние:

var state = e.Graphics.Save();

а потом восстановить:

e.Graphics.Restore(state);

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

Реза Агаи клонирует объект GraphicsPath. Для этого, вероятно, потребуется e.Graphics.ResetTransform после (да, я знаю, что вы это знаете :).
Jimi 07.01.2019 18:47

Другие вопросы по теме