For the first part of your question do have a look at this post, which has a reduction function for a List<Point>
. Note that the GraphicsPath.PathPoints
collection is read-only, so you have to re-create the path from the reduced points list.
A few remarks on the second part:
There is no built-in routine to create the handles. Nor to make them do anything. So you need to code for them.
I append a simple class MoveLabel
which can be used for this. It can be placed on a control or be added to its Controls
collection. Then you can move it around. I have added a callback function MoveAction
to process the result when the mouse is released.
You can either add a ..
public delegate void Moved(MoveLabel sender);
..to the form class, or, to avoid the Form1
reference, outside of the form class but in scope for the MoveLabel
.
It can be used directly to move points in points list:
Create it on a panel:
var lab= new MoveLabel(Color.CadetBlue, 9, Point.Round(points[i]), i);
lab.Parent = panel;
lab.MoveAction = moved;
A simple processing function:
void moved(MoveLabel sender)
{
points[sender.PointIndex] =
new Point(sender.Left - sender.Width / 2, sender.Top - sender.Height / 2);
panel.Invalidate();
}
Note that the GraphicsPath.PathPoints
are read-only, so we have to re-create the path from the new points list! Actually one can modify individual PathPoints
in code, but the result does not stick; so one has to copy the PathPoints
to a PointF[]
, modify them there and re-create the path. For complex paths best by using this overload..
If you want to implement a rotation (or other transformations) you can use the GraphicsPath.Transform function. You can use moveable labels to determine the rotation or scaling data..
Here is my minimal MoveLabel
class:
public class MoveLabel : Label
{
public Form1.Moved MoveAction { get; set; }
public int PointIndex { get; set; }
private Point mDown = Point.Empty;
public MoveLabel()
{
MouseDown += (ss, ee) => { mDown = ee.Location; };
MouseMove += (ss, ee) => {
if (ee.Button.HasFlag(MouseButtons.Left))
{
Location = new Point(Left + ee.X - Width / 2, Top + ee.Y - Height / 2);
mDown = Location;
}
};
MouseUp += (ss, ee) => { if (MoveAction != null) MoveAction(this); };
}
public MoveLabel(Color c, int size, Point location, int pointIndex) : this()
{
BackColor = Color.CadetBlue;
Size = new Size(size, size);
Location = location;
PointIndex = pointIndex;
}
}
This will also work fine to move points from bezier curves. By adding a call MoveAction(this);
to the MouseMove
linq code you can get live updates.. Make sure the Panels
are DoubleBuffered for this :-)
Example:

Btw: I just came upon this post which shows how easily the curve or any other GDI+ vector drawing can be saved to emf
, preserving the vector quality!
Update: Instead of a Panel
, which is a Container
control and not really meant to draw onto you can use a Picturebox
or a Label
(with Autosize=false
); both have the DoubleBuffered
property turned on out of the box and support drawing better than Panels
do.