0

Here goes... I need to draw several annular sectors in VisualBasic.NET using a GraphicsPath.

I would for instance enter the annular sector's outer and inner diameter/radius and a starting and ending degree/radiant. The function must then return a GraphicsPath that can simply be added to another GraphicsPath as a closed shape. This seems very easy to do, but I need it to keep a 5 pixel gap between the annular sectors.

I will explain more... If for instance I enter 0 degrees as starting point and 360 degrees as ending point it must return a GraphicsPath with an annular sector that starts at X degrees (where X is 2.5 pixels offset from 0 degrees) and ends at Y degrees (where Y is -2.5 pixels offset from 360 degrees). Both the outer and inner curves of the annular sector must adhere to the above. It basically must be as if I drew two parallel lines 5 pixels apart through the circle's center at the degrees entered and used the lines as starting and ending points for the arcs. This must hold true for any Degrees entered.

This post: SVG donut slice as path element (annular sector) Almost solves the problem, but it draws all annular sectors from the center point (not unlike Pie slices) outwards causing consecutive outer rings to have bigger and bigger gaps in between if you split them with 1 Degree each time (plus it is for SVG).

I include an image explaining what I am trying to say better: https://onedrive.live.com/redir?resid=79292E5BC057FE03!112&authkey=!AMnkq0bjbsH4BwU&v=3&ithint=photo%2cjpg

This question was solved by valter. Scroll down to EDIT 2 in his answer for the code.

This image: (https://onedrive.live.com/redir?resid=79292E5BC057FE03!113&authkey=!AGxrnpf8MiiEX48&v=3&ithint=photo%2cjpg) shows what can be achieved with his solution.

The following code was used to create the GraphicsPath used to draw the pie and annular sectors in the image. At the time of writing this negative sweepA (sweep angle) was not supported.

Dim p As GraphicsPath = New GraphicsPath()
p.AddPie(160.0F, 160.0F, 280.0F, 280.0F, 300.0F, 90.0F)
p.AddPath(DrawAnnular(New Point(300I, 300I), 100I, 70I, 300.0F, 90.0F, 5.0R), False)
p.AddPath(DrawAnnular(New Point(300I, 300I), 100I, 70I, 30.0F, 80.0F, 5.0R), False)
p.AddPath(DrawAnnular(New Point(300I, 300I), 135I, 105I, 300.0F, 90.0F, 5.0R), False)
p.AddPath(DrawAnnular(New Point(300I, 300I), 135I, 105I, 30.0F, 80.0F, 5.0R), False)

Thanks

drifter

Community
  • 1
  • 1
drifter
  • 5
  • 4
  • You just need to calculate the new center(intersect point of the two parallel lines) and the new inner outer dimensions. If you know some basic geometry (equations of lines, intersect points etc..) it is not so hard – γηράσκω δ' αεί πολλά διδασκόμε Sep 08 '14 at 12:41
  • @valter. Very observant comment though not very useful to me in solving my problem. I know the chord geometry to get the offset and to get the point on a circle's edge. I extensively played with several ideas before posting here. I just can't seem to get it all together in a calculation that actually works. Not even to mention that to get the arcs you need to give vb a rectangle or estimated bezier curve. – drifter Sep 08 '14 at 16:55
  • I can give you code that draws an annular but not a path. A path is more difficult – γηράσκω δ' αεί πολλά διδασκόμε Sep 08 '14 at 18:06
  • @valter. That will be greatly appreciated. I think in the end I will have to use Bezier estimations to draw the arcs, since the way you create an arc in vb is very limited. – drifter Sep 08 '14 at 19:43

1 Answers1

0

pntC is the center. outerR and innerR are the radius. startA and endA are the angles. The angles are measured from x axis and clockwise

Private Sub DrawAnnular(ByVal pntC As Point, ByVal outerR As Integer, ByVal innerR As Integer, ByVal startA As Integer, ByVal endA As Integer)
    Dim g As Graphics
    Dim mypen As New Pen(Color.FromKnownColor(KnownColor.Control), 1) 'the form back color
    Dim mybrush As New SolidBrush(Color.FromKnownColor(KnownColor.Control)) 'the form back color

    g = Me.CreateGraphics
    g.SmoothingMode = SmoothingMode.AntiAlias

    g.FillPie(Brushes.Black, pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA, -startA + endA) 'Outer
    g.FillPie(mybrush, pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA, -startA + endA) 'Inner

    g.DrawPie(mypen, pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA, -startA + endA) 'Outer
    g.DrawPie(mypen, pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA, -startA + endA) 'Inner

    g.Dispose()
End Sub

EDIT

This is an example of how to find the GraphicPath with the gap.

enter image description here

Dim pth As New GraphicsPath

pth.AddArc(outArc)

pth.AddLine(D, C)

pth.AddArc(innArc)

pth.AddLine(A, B)

and there is your path. Lets find A, B (the same logic applies to C, D):

ε1 : y = a * x + b
ε1': y = a * x + (b +- 2,5) we keep the minus in this example

a is known (the angle of ε1 with x axis) and b can be calculated (pntC belongs to ε1):

pntC.Υ = a * pntC.X + b

Now we have to find the intercept points of ε1' with outer circle(B) and with inner circle(A):

Solve these equations for x, y (point B)

circle: (x - pntC.X) * (x - pntC.X) + (y - pntC.Y) * (y - pntC.Y) = outerR * outerR
ε1'   : y = a * x + (b - 2,5)

Solve these equations for x, y (point A)

circle: (x - pntC.X) * (x - pntC.X) + (y - pntC.Y) * (y - pntC.Y) = innerR * innerR
ε1'   : y = a * x + (b - 2,5)

Now we need to valculate outArc, innArc. outArc (the same logic applies for innerArc):

enter image description here

pth.AddArc(outArc): pth.AddArc(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA + φ, endA - startA - 2 * φ)

Calculating φ (OBB' triangle):

enter image description here

sinφ = OB'/OB => sinφ = 2,5 / outerR

One last thing. Because Form coordinates are opposite from real ones (only for Y axis), before using pntC for your calculation, convert to real one :

real: pntC.Yr = (Form client Height) - pntC.Y

and when you calculate A, B, C, D, transform to Form ones (the r means real):

A.Y = (Form client Height) - A.Yr
B.Y = (Form client Height) - B.Yr
C.Y = (Form client Height) - C.Yr
D.Y = (Form client Height) - D.Yr

EDIT 2

With the gap:

Private Sub DrawAnnular(ByVal pntC As Point, ByVal outerR As Integer, ByVal innerR As Integer, ByVal startA As Single, ByVal sweepA As Single, ByVal gap As Double)
    Dim g As Graphics
    Dim pth As New GraphicsPath
    Dim fe, dbl As Double 'fe is "φ"

    gap = gap / 2.0R

    g = Me.CreateGraphics
    g.SmoothingMode = SmoothingMode.AntiAlias

    dbl = gap / CDbl(outerR)
    fe = Math.Asin(dbl) * 180.0R / Math.PI

    pth.AddArc(pntC.X - outerR, pntC.Y - outerR, 2 * outerR, 2 * outerR, startA + CSng(fe), sweepA - CSng(2.0R * fe)) 'Outer

    dbl = gap / CDbl(innerR)
    fe= Math.Asin(dbl) * 180.0R / Math.PI

    pth.AddArc(pntC.X - innerR, pntC.Y - innerR, 2 * innerR, 2 * innerR, startA + sweepA - CSng(fe), -(sweepA - CSng(2.0R * fe))) 'Inner

    g.FillPath(Brushes.Black, pth)

    pth.Dispose()
    g.Dispose()
End Sub

valter

  • Thanks for the code, but unfortunately this does not do what I need. When you draw pies and erase parts of them artifacts stay behind (especially on the edges and especially when you use anti-alias in combination with scaling). I have exhausted FillPie and it left me frustrated to say the least. I may be wrong, but I can also not find the part in your code that compensates as described in my original question: i.e: [...`startA, -startA + endA)`] is just using the degrees given and not compensating to leave a parallel gap of 5 pixels. – drifter Sep 08 '14 at 22:45
  • @drifter I didn't say that this is the answer with the gap. It just draws an anular. It was a little help because you had a problem doing anything, your words *Not even to mention that to get the arcs you need to give vb a rectangle or estimated bezier curve* – γηράσκω δ' αεί πολλά διδασκόμε Sep 09 '14 at 02:44
  • I don't want to argue with you. You obviously took offense to something I said so I apologize. Maybe I misunderstood what you were offering (You should have included the above quote with your offer then I would have declined the code realizing that you misunderstood my question). Just to be clear though: It is a dirty job to draw custom arcs in VB, but I never said I can't do it. I merely meant that the way I am trying to do it here may not work so I might have to consider estimated Beziers. I am looking for help on the Math as it pertains to VisualBasic.NET. – drifter Sep 09 '14 at 04:29
  • I just saw your edit of your answer and will give it a go in VB as soon as the coffee kicks in. Thanks the effort. – drifter Sep 09 '14 at 10:06
  • You obviously went to a great deal of trouble to draw/type up your answer and I appreciate it greatly. Unfortunately most of us weekend coders need word sums so I may have wasted your time. I get stuck on the first line: `ε1 : y = a * x + b`. I assume `a` would be `startA`, but cannot figure out what `x` represents. On line two `pntC` is introduced and it belongs to `ε1`. Is this the center point of the circle? However all is not lost. I typed up a code solution shell in my question. If you can solve it within the bounds of that solution I will gladly tick your answer as accepted. – drifter Sep 09 '14 at 13:11
  • Dude! This works like a charm! Thanks! I want to close this question, but we first need to clean up a bit. Can you please fix 'Edit2' it so `gap` is first divided by two (sure you can figure out why). Also values of `startA=300.0F` & `endA=30.0f` must not draw the sector the wrong way around. Even better would be to just change `endA` to `sweepA` like the `AddArc` expects. I can fix it myself and post it in the original question if you don't feel like it, but I want to mark your question as the solution. There are way too many solved questions on here that is still open. – drifter Sep 10 '14 at 13:41
  • Thanks so much for your help. I have closed the question and marked your answer as accepted, but you may want to fix the second `AddArc` still says `endA`. I think it should be `(startA + sweepA)`. I think the `AddArc` method won't care if `startA + sweepA` is bigger than 360 degrees. Thanks again. – drifter Sep 10 '14 at 15:56