def makeroots(self, rootbases, mcmap):
        '''generate the roots and enter them in mcmap.

        rootbases = [[x, z, base_radius], ...] and is the list of locations
        the roots can originate from, and the size of that location.
        '''
        treeposition = self.pos
        height = self.height
        for coord in self.foliage_cords:
            # First, set the threshhold for randomly selecting this
            # coordinate for root creation.
            dist = (sqrt(float(coord[0] - treeposition[0]) ** 2 +
                         float(coord[2] - treeposition[2]) ** 2))
            ydist = coord[1] - treeposition[1]
            value = (self.branchdensity * 220 * height) / ((ydist + dist) ** 3)
            # Randomly skip roots, based on the above threshold
            if value < random():
                continue
            # initialize the internal variables from a selection of
            # starting locations.
            rootbase = choice(rootbases)
            rootx = rootbase[0]
            rootz = rootbase[1]
            rootbaseradius = rootbase[2]
            # Offset the root origin location by a random amount
            # (radialy) from the starting location.
            rndr = (sqrt(random()) * rootbaseradius * .618)
            rndang = random() * 2 * pi
            rndx = int(rndr * sin(rndang) + 0.5)
            rndz = int(rndr * cos(rndang) + 0.5)
            rndy = int(random() * rootbaseradius * 0.5)
            startcoord = [rootx + rndx, treeposition[1] + rndy, rootz + rndz]
            # offset is the distance from the root base to the root tip.
            offset = [startcoord[i] - coord[i] for i in range(3)]
            # If this is a mangrove tree, make the roots longer.
            if SHAPE == "mangrove":
                offset = [int(val * 1.618 - 1.5) for val in offset]
            endcoord = [startcoord[i] + offset[i] for i in range(3)]
            rootstartsize = (rootbaseradius * 0.618 * abs(offset[1]) /
                             (height * 0.618))
            if rootstartsize < 1.0:
                rootstartsize = 1.0
            endsize = 1.0
            # If ROOTS is set to "tostone" or "hanging" we need to check
            # along the distance for collision with existing materials.
            if ROOTS in ["tostone", "hanging"]:
                offlength = sqrt(float(offset[0]) ** 2 +
                                 float(offset[1]) ** 2 +
                                 float(offset[2]) ** 2)
                if offlength < 1:
                    continue
                rootmid = endsize
                # vec is a unit vector along the direction of the root.
                vec = [offset[i] / offlength for i in range(3)]
                if ROOTS == "tostone":
                    searchindex = STOPSROOTS
                elif ROOTS == "hanging":
                    searchindex = [0]
                # startdist is how many steps to travel before starting to
                # search for the material.  It is used to ensure that large
                # roots will go some distance before changing directions
                # or stopping.
                startdist = int(random() * 6 * sqrt(rootstartsize) + 2.8)
                # searchstart is the coordinate where the search should begin
                searchstart = [startcoord[i] + startdist * vec[i]
                               for i in range(3)]
                # dist stores how far the search went (including searchstart)
                # before encountering the expected marterial.
                dist = startdist + dist_to_mat(searchstart, vec,
                                               searchindex, mcmap, limit=offlength)
                # If the distance to the material is less than the length
                # of the root, change the end point of the root to where
                # the search found the material.
                if dist < offlength:
                    # rootmid is the size of the crossection at endcoord.
                    rootmid += (rootstartsize -
                                endsize) * (1 - dist / offlength)
                    # endcoord is the midpoint for hanging roots,
                    # and the endpoint for roots stopped by stone.
                    endcoord = [startcoord[i] + int(vec[i] * dist)
                                for i in range(3)]
                    if ROOTS == "hanging":
                        # remaining_dist is how far the root had left
                        # to go when it was stopped.
                        remaining_dist = offlength - dist
                        # Initialize bottomcord to the stopping point of
                        # the root, and then hang straight down
                        # a distance of remaining_dist.
                        bottomcord = endcoord[:]
                        bottomcord[1] += -int(remaining_dist)
                        # Make the hanging part of the hanging root.
                        self.taperedcylinder(endcoord, bottomcord,
                                             rootmid, endsize, mcmap, WOODINFO)

                # make the beginning part of hanging or "tostone" roots
                self.taperedcylinder(startcoord, endcoord,
                                     rootstartsize, rootmid, mcmap, WOODINFO)

            # If you aren't searching for stone or air, just make the root.
            else:
                self.taperedcylinder(startcoord, endcoord,
                                     rootstartsize, endsize, mcmap, WOODINFO)
generate the roots and enter them in mcmap.

        rootbases = [[x, z, base_radius], ...] and is the list of locations
        the roots can originate from, and the size of that location.
        
stock-filters/Forester.py