def __init__(self, ratio=0.8, angle=pi/2., ngen=3, nbran=2):
        """
        ratio: ratio of branch length with respect to previous generation
        angle: fan angle, how wide spread the branches will be (0<angle<2*pi)
        ngen: number of generations.
        nbran: number of new branches.
        """
        # coords in complex notation
        self.ratio = ratio
        self.angle = angle
        self.ngen  = ngen
        self.nbran = nbran
        # the root is at (0,0)
        # the top of the trunk is at position (0,1), this will be the
        # starting node
        self.pts2xy = {(-1,0): 0j, (0,0): 1j}
        self.xmax, self.ymax = 0, 1
        alpha_0     = angle/2.
        delta_alpha = angle / float(nbran-1)
        for i in range(1, ngen):
            for j in range(nbran**i):
                # child
                ij = (i,j)
                # parent
                kl = get_parent_indices(i, j, nbran)
                k, l = kl
                xy_kl = self.pts2xy[kl]
                xy_mn = self.pts2xy[(k-1, l//nbran)] 
                ph_ij = atan2(xy_kl.imag - xy_mn.imag, xy_kl.real - xy_mn.real)
                self.pts2xy[ij] = self.pts2xy[kl] + \
                                  ratio**i * \
                                  exp(1j*(ph_ij+ alpha_0 - (j%nbran)*delta_alpha))
                x, y = self.pts2xy[ij].real, self.pts2xy[ij].imag
                self.xmax = max(x, self.xmax)
                self.ymax = max(y, self.ymax)

        ratio: ratio of branch length with respect to previous generation
        angle: fan angle, how wide spread the branches will be (0<angle<2*pi)
        ngen: number of generations.
        nbran: number of new branches.
        
recipes/Python/410158_Fractal_tree/recipe-410158.py