Как создать зеркальную форму на графике - PullRequest
0 голосов
/ 07 января 2019

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

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]);

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

mirror image

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

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

это что-то вроде копирования и переворачивания графики и составных?

Спасибо

Ответы [ 3 ]

0 голосов
/ 07 января 2019

Имея 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 использует правую сторону пути в качестве оси.

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

enter image description here

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

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);
}
0 голосов
/ 07 января 2019

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

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);

enter image description here

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

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

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

var state = e.Graphics.Save();

и затем восстановить его:

e.Graphics.Restore(state);

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

0 голосов
/ 07 января 2019

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

Некоторые API напрямую поддерживают отражение, например Vector2.Reflect :

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

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

enter image description here

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

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 + преобразование представляется объектом Matrix . Отражение недоступно, но его можно заменить на Matrix.Scale , если мы хотим отразить только по осям X или Y. Например:

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

Отражает массив точек, умножая все значения X на 1 и все значения Y на -1.

...