I have the following PathPoints and PathTypes arrays (format: X, Y, Type):
-177.477900, 11021.670000, 1
-614.447200, 11091.820000, 3
-1039.798000, 10842.280000, 3
-1191.761000, 10426.620000, 3
-1591.569000, 10493.590000, 3
-1969.963000, 10223.770000, 3
-2036.929000, 9823.960000, 3
-2055.820000, 9711.180000, 3
-2048.098000, 9595.546000, 3
-2014.380000, 9486.278000, 3
Here is what this GraphicsPath physically looks like. The 2 Arcs are very distinguishable:
I know that this GraphicsPath.PathData array was created by 2 AddArc commands. Stepping through the code in the debugger, I saw that the first 4 PathData values were added by the first AddArc command, and the remaining 6 points were added by the 2nd AddArc command.
By examining the raw pathpoints/pathtype arrays (without previously knowing that it was 2 AddArc commands so I would know that I have 2 start and end points), I would like to determine to start and end point of each arc.
I have tried several Bezier calculations to 'recreate' the points in the array, but am at a loss to determine how to determine the separate start and end points. It appears that GDI+ is combining the start/end point between the arcs (they are the same point and the arcs are connected), and I am losing the fact that one arc is ending and other one is starting.
Any ideas?
Use the GraphicsPathIterator class in combination with the GraphicsPath.SetMarkers method.
For example:
dim gp as new GraphicsPath
gp.AddArc(-50, 0, 100, 50, 270, 90) 'Arc1
gp.SetMarkers()
gp.AddArc(0, 25, 100, 50, 270, 90) 'Arc2
Dim iterator as New GraphicsPathIterator(gp)
Dim i as Integer = 0
Dim MyPts(3) As PointF
Dim temp as New GraphicsPath
Do until i > 2
iterator.NextMarker(temp)
MyPts(i) = temp.PathPoints(0)
MyPts(i + 1) = temp.GetLastPoint()
i += 2
Loop
'Free system resources...
iterator.Dispose()
temp.Dispose()
Arc1 -> start: MyPts(0); end: MyPts(1)
Arc2 -> start: MyPts(2); end: MyPts(3)
Hope this helps!
Take a look at the PathPointType Enum (System.Drawing.Drawing2D).
Value Meaning
0 Start (path)
1 Line
3 Bezier/Bezier3
7 PathType Mask
16 Dash Mode
32 Path Marker
128 Close Subpath
This one was bugging me a lot too! I had path created beyond my control without markers and couldn't figure out curve endpoints.
In this case you'd expect that the curve starts at [i + 1]
but it is not! It turns out that GDI combines path points probably to make the points array shorter. In this case the curve points are: [0], [1], [2], [3]
.
It seems that if PathPointType.Start
or PathPointType.Line
is followed by PathPointType.Bezier
, then you have to treat the PathPontType.Start
or Path.PointType.Line
as a first point of your Bezier curve, so in your example it should be like this:
-177.47, 11021.67, 1 // Draw line to this point AND use it as a Bezier start!
-614.44, 11091.82, 3 // Second Bezier point
-1039.79, 10842.28, 3 // Third Bezier point
-1191.76, 10426.62, 3 // Fourth Bezier point AND first point of the next Bezier!
-1591.56, 10493.59, 3 // Second Bezier point
-1969.96, 10223.77, 3 // Third Bezier point
-2036.92, 9823.96, 3 // Fourth Bezier point AND first point of the next Bezier!
-2055.82, 9711.18, 3 // Second Bezier point
-2048.09, 9595.54, 3 // Third Bezier point
-2014.38, 9486.27, 3 // Fourth Bezier point
So, when analysing PathPoints
array point by point, you have to also check current and following indices. The docs on PatPointType might come in handy. In most cases you can probably ignore additional data stored on bits other than the first three (these three define Start
, Line
and Bezier
). The only exception is CloseSubpath
but it's irrelevant if you consider the next advice.
It's also worth noting that if you have a complex path that consists of huge number of PathPoints
then it might be handy to split the path into chunks using GraphicsPathIterator. This simplifies the whole procedure as PathPointType.CloseSubpath
can be ignored - it will be always the last point of your GraphicsPath
chunk.
A quick look into Reflector or here might be helpful if you want to better understand PointTypes
array.