For the examples that I posted previously, I was using a fairly bulky subroutine to rotate and position the text. It has far more bells and whistles than is needed here. I’ve now had a bit of time to pare things down to a more reasonable size and have created a subroutine for drawing the fan chart text. The main fan chart subroutine has also been slightly revised so that it takes the root person node (the person at the centre of the chart) as a parameter, and then traverses the family tree to get all of the text information to be displayed. For this I’m assuming that all of the family tree data already exists and the ‘person’ class contains the following properties:
class person
  Public Property Name as string
  Public Property Birth as date
  Public Property Marriage as date
  Public Property Death as date
  Public Property father as Person
  Public Property mother as Person
  Public Property Children() as Person
end class
The children() property is not necessary for this example, but would likely be required for a general family tree application to allow traversing the tree in both directions
This is the subroutine that draws the rotated text:
Public Sub DrawNodeText(g As Graphics,xOrigin as integer,yOrigin as integer, node As Integer, p As Person,radius As Double,radIncr As Double,angle As Double,fsize As Double)
  'Draws person's name and vital dates on fan chart
  ' as rotated text, at the given the origin, angle, 
  ' radius, and incremental radial distance between items.
  
  Const pi = 3.14159265358979
  
  dim x,y,i,w,h As Integer
  dim rad,txtRot As Double
  dim output() As string 
  dim s As new StringShape
  Dim pTest as new Picture(1,1)
  
  'Allow different text styles for each text item
  static txtClr() As Color = Array(&c000000,&c050580,&c000000,&c000000,&c000000)
  static textBold() As Boolean = Array(false,true,false,false,false)
  
  'Text is perpendicular to the radial angle
  txtRot=pi*0.5-angle
  
  'Text parameters
  s.TextFont = "Times"
  s.TextSize = fsize
  s.HorizontalAlignment = StringShape.Alignment.Left
  s.VerticalAlignment = StringShape.Alignment.Bottom
  s.Rotation = txtRot
  'Test picture pTest is used for measuring stringshape width and height
  ' using a method suggested by Alwyn Bester
  pTest.Graphics.TextFont = s.TextFont
  pTest.Graphics.TextSize = s.TextSize
  pTest.Graphics.TextUnit = s.TextUnit
  
  'Load text items into array
  output=array(str(node),p.Name,"b. "+p.Birth.ShortDate,"","")
  'Person may be alive and/or unmarried so check for nil dates
  if p.Marriage <> nil then output(3) = "m. "+p.Marriage.ShortDate
  if p.Death <> nil then output(4) = "d. "+p.Death.ShortDate
  
  'Draw the text
  for i = 0 to UBound(output)
    rad = radius-i*radIncr
    s.Bold = textBold(i)
    s.FillColor = txtClr(i)
    s.Text = output(i)
    pTest.Graphics.Bold = s.Bold
    'Get the half-width and half-height of the unrotated text
    w = pTest.Graphics.StringWidth(s.Text)/2
    h = pTest.Graphics.StringHeight(s.Text,10000)/2
    'Locate the text origin
    x = (rad-h)*cos(angle)+xOrigin-cos(txtRot)*w
    y = (rad-h)*sin(angle)+yOrigin+sin(txtRot)*w
    g.DrawObject(s,x,g.height-y)
  next
End Sub
And this is the revised original fanchart subroutine, along with subroutine AddToFam which retrieves the data from the family tree structure:
Public Sub Fanchart(gg As Graphics, size As Integer,depth As Integer, p As Person)
  'Input parameters:
  ' Depth - number of concentric rings not counting the inner one
  '   i.e.,  the depth of family tree to be displayed
  ' Size - the radius of the overall chart in pixels
  ' (Text size is automatically scaled to the chart size)
  dim x1,y1,x2,y2,radiusStart,radiusInitial,radiusIncr,pen As Integer
  dim xOrigin,yOrigin,i,j,k As Integer
  dim angle,InnerRatio As Double
  dim arc As new ArcShape
  Const pi=3.14159265358979
  'The following scaled up picture is used temporarily 
  ' to mitigate Object2D grainy resolution problems
  ' 4x may be a bit excessive, but it looks nice :-)
  dim scalePic As new Picture(gg.Width*4,gg.Height*4)
  dim g As Graphics = scalePic.graphics
  'Probably the most convenient way to get text from 
  ' family tree structure is to transfer it to an array.
  ' so that it is arranged in fan chart node order.
  dim family() As Person
  ReDim family(2^(depth+1)-1)
  'Fill out the array recursively starting with person 'p'
  ' the person at the centre of the fanchart
  AddToFam(p,1,family)
  'Graphics setup stuff
  pen=3
  g.ForeColor=&c000000
  g.PenHeight=pen
  g.PenWidth=pen
  'Adjust the origin to suit. These determine the centre of the semicircle
  ' as measured from the bottom left side of the canvas.
  xOrigin=g.width\\2
  yOrigin=50
  arc.ArcAngle = pi
  arc.StartAngle = -pi
  arc.Fill=0
  arc.Border=100
  arc.BorderWidth=pen
  arc.Segments=128
  InnerRatio=0.8 'Allows radius of inner semicircle to be different than the others
  radiusIncr=size/(depth+InnerRatio)
  radiusInitial=radiusIncr*InnerRatio
  'Draw outer arc
  arc.Height=size*2
  arc.Width=size*2
  g.DrawObject(arc, xOrigin,g.height-yOrigin)
  'Draw base line
  g.DrawLine(xorigin-radiusInitial-depth*radiusIncr,g.height-yOrigin,_
  xorigin+radiusInitial+depth*radiusIncr,g.height-yOrigin)
  dim NodeNumber As Integer = 1
  'Node 1 text
  angle=pi/2
  DrawNodeText(g,xOrigin,yOrigin,NodeNumber,family(NodeNumber),_
  0.9*radiusInitial,0.12*radiusIncr,angle,size*0.02)
  'Draw remaining arcs, radials, text
  for i=1 to depth
    radiusStart = radiusInitial+(i-1)*radiusIncr
    arc.Height=radiusStart*2
    arc.Width=radiusStart*2
    g.DrawObject(arc, xOrigin,g.height-yOrigin)
    k=2^i
    'Draw radial lines
    for j = 1 to k-1 step 2
      angle=pi*j/k
      x1=radiusStart*cos(angle)+xOrigin
      y1=radiusStart*sin(angle)+yOrigin
      x2=size*cos(angle)+xOrigin
      y2=size*sin(angle)+yOrigin
      g.DrawLine(x1,g.height-y1,x2,g.height-y2)
    next
    'Draw text
    for j=k-1 downto 0
      NodeNumber=NodeNumber+1
      angle=pi*(j+0.5)/(k)
      DrawNodeText(g,xOrigin,yOrigin,NodeNumber,family(NodeNumber),_
      radiusStart+0.9*radiusIncr,0.15*radiusIncr,angle,size*0.02)
    next
  next
  gg.DrawPicture(scalePic,0,0,gg.Width,gg.Height,0,0,g.Width,g.Height)
End Sub
Public Sub AddToFam(p As Person,index As Integer,fam() As person)
  'Recursively fills the family array for the fan chart
  if index>UBound(fam) then return
  fam(index)=p
  if p.father <> Nil then addToFam(p.father,index*2,fam)
  if p.Mother <> Nil then addToFam(p.mother,index*2+1,fam)
End Sub
Caveat: I’ve only tested this on a Mac (OSX 10.10.5). I don’t expect any platform specific issues, but you never know.