First of all big thank you to the person who answered this question How to drag and move shapes in C# and this is all based off that. I'm only starting to work with c# and WinForms so I would really appreciate any advice.
I have interface IShape
and classes that implement it(Star, Rhombus). I need to display shapes on the form and move, rotate and scale them. So far I have this. I can select and move shapes. I'm not sure how to rotate a polygon using matrix, since my draw method uses GetPath()
and it creates a new path every time a redraw the image and I can not modify points inside that path.
Should I create another graphics path from the original one and rotate it or do something else? Any help would be greatly appreciated.
IShape
using System;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading.Tasks;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
namespace GSC_LR4
{
interface IShape
{
GraphicsPath GetPath();
bool Selected(PointF p);
void Draw(Graphics g);
void Move(PointF m);
PointF Min();
PointF Max();
PointF Center();
//void Zoom(PointF z);
//void Mirrored(PointF h);
GraphicsPath GetRotatedPath();
void GetBorders();
//void Delete(PointF s);
void VertexClear();
void DrawSelection(Graphics e)
}
}
Rhombus
using System;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading.Tasks;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
namespace GSC_LR4
{
class Rhombus : IShape
{
List<PointF> VertexList { get; set; }
public PointF maxPoint;
public PointF minPoint;
public PointF center;
public Color oColor { get; set; }
public Rhombus(PointF p)
{
VertexList = new List<PointF>();
maxPoint = new PointF();
minPoint = new PointF();
center = p;
}
public Rhombus(List<PointF> vertexes, Color color)
{
VertexList = vertexes.ConvertAll(item => new PointF(item.X, item.Y));
maxPoint = new PointF();
minPoint = new PointF();
oColor = color;
}
public Rhombus(Color Color)
{
center = new PointF(150, 150);
oColor = Color;
}
public GraphicsPath GetPath()
{
var path = new GraphicsPath();
PointF[] VertexRhomb = new PointF[4];
VertexRhomb[0].X = center.X - 80;
VertexRhomb[0].Y = center.Y;
VertexRhomb[1].X = center.X;
VertexRhomb[1].Y = center.Y - 100;
VertexRhomb[2].X = center.X 80;
VertexRhomb[2].Y = center.Y;
VertexRhomb[3].X = center.X;
VertexRhomb[3].Y = center.Y 100;
// VertexList.AddRange(VertexRhomb.ToArray());
path.AddPolygon(VertexRhomb.ToArray());
return path;
}
public GraphicsPath GetRotatedPath()
{
var path = new GraphicsPath();
List<PointF> temp = new List<PointF>();
temp.AddRange(GetPath().PathPoints);
path.AddPolygon(temp.ToArray());
Matrix rotateMtx = new Matrix();
//rotateMtx.Translate(center.X, center.Y);
rotateMtx.RotateAt(45f, center);
//rotateMtx.Translate(-center.X, -center.Y);
path.Transform(rotateMtx);
return path;
}
public void Draw(Graphics g)
{
using(var path = GetPath())
using (var brush = new SolidBrush(oColor))
g.FillPath(brush, path);
}
public void Move(PointF d)
{
center = new PointF(center.X d.X, center.Y d.Y);
}
public bool Selected(PointF p)
{
bool selected = false;
using (var path = GetPath())
selected = path.IsVisible(p);
return selected;
}
public void GetBorders()
{
minPoint.X = VertexList.Min(item => item.X);
minPoint.Y = VertexList.Min(item => item.Y);
maxPoint.X = VertexList.Max(item => item.X);
maxPoint.Y = VertexList.Max(item => item.Y);
}
public PointF Min()
{
PointF p = new PointF();
p.X = GetPath().PathPoints.Min(item => item.X);
p.Y = GetPath().PathPoints.Min(item => item.Y);
//p.X = VertexList.Min(item => item.X);
//p.Y = VertexList.Min(item => item.Y);
return p;
}
public PointF Max()
{
PointF p = new PointF();
//p.X = VertexList.Max(item => item.X);
//p.Y = VertexList.Max(item => item.Y);
p.X = GetPath().PathPoints.Max(item => item.X);
p.Y = GetPath().PathPoints.Max(item => item.Y);
return p;
}
public PointF Center()
{
PointF Pmin = Min();
PointF Pmax = Max();
return new PointF((Pmax.X Pmin.X) / 2, (Pmax.Y Pmin.Y) / 2);
}
public void VertexClear()
{
VertexList.Clear();
}
public void DrawSelection(Graphics e)
{
int Xmin = (int)Min().X,
Ymin = (int)Min().Y;
int Xmax = (int)Max().X,
Ymax = (int)Max().Y;
Pen pen = new Pen(Color.Gray);
pen.DashStyle = DashStyle.Dash; // штрихованная линия
e.DrawRectangle(pen, new Rectangle(Xmin, Ymin, Xmax - Xmin, Ymax - Ymin));
}
//public void Rotate()
//{
//double cos = Math.Cos(45 * Math.PI / 180); //maybe refactor
//double sin = Math.Sin(45 * Math.PI / 180);
//PointF[] VertexRhomb = new PointF[4];
//for (int i = 0; i < GetPath().PointCount; i ) //sides = 6?
//{
// PointF p = new PointF();
// p.X = (float)((VertexRhomb[i].X - center.X) * cos - (VertexRhomb[i].Y - center.Y) * sin center.X);
// p.Y = (float)((VertexRhomb[i].X - center.X) * sin (VertexRhomb[i].Y - center.Y) * cos center.Y);
// VertexRhomb[i] = new PointF(p.X, p.Y);
// //p.X = (float)(cos * ((GetPath().PathPoints[i].X) - Center().X) - sin * ((GetPath().PathPoints[i].Y) - Center().Y) (Center().X));
// //p.Y = (float)(sin * ((GetPath().PathPoints[i].X) - Center().X) cos * ((GetPath().PathPoints[i].Y) - Center().Y) (Center().Y))
//}
//GetPath().AddPolygon(VertexRhomb.ToArray());
//Matrix rotateMtx = new Matrix();
//rotateMtx.Translate(center.X, center.Y);
//rotateMtx.RotateAt(45f, center);
//rotateMtx.Translate(-center.X, -center.Y);
//using (var path = GetPath())
//GetPath().Transform(rotateMtx);
//}
}
}
The code is messy I'm sorry about it but you can look at me attempts.
CodePudding user response:
Have a single method to create and return the GraphicsPath
object and add properties to the interface or the implement class (depending on the shape) that defines how the path should be created and what translation and/or transformations should be applied if any.
Since any shape can be rotated, scaled, and translated, then the IShape
interface is the right place to have abstract properties for these operations.
IShape
Covering here the rotation as requested.
public interface IShape
{
GraphicsPath GetPath();
float RotationAngle { get; set; }
// ...etc.
}
Rhombus
The relevant implementation.
public class Rhombus : IShape
{
//...
public float RotationAngle { get; set; }
public GraphicsPath GetPath()
{
var path = new GraphicsPath();
var VertexRhomb = new[]
{
new PointF(center.X - 80, center.Y),
new PointF(center.X, center.Y - 100),
new PointF(center.X 80, center.Y),
new PointF(center.X, center.Y 100)
};
path.AddPolygon(VertexRhomb.ToArray());
if (RotationAngle != 0)
{
var mx = new Matrix();
mx.RotateAt(RotationAngle, center);
path.Transform(mx);
}
return path;
}
public void Draw(Graphics g)
{
using (var path = GetPath())
using (var brush = new SolidBrush(oColor))
g.FillPath(brush, path);
}
}
Don't forget to call yourDrawingCanvas.Invalidate();
when you set a new rotation value.