示例#1
0
    def to_polygon(self):
        """Return a rectangular :class:`~planar.Polygon` object with the same
        vertices as the bounding box.

        :rtype: :class:`~planar.Polygon`
        """
        return planar.Polygon([
            self._min, (self._min.x, self._max.y), 
            self._max, (self._max.x, self._min.y)],
            is_convex=True)
示例#2
0
	def __init__(self, verts, *args):
		# print('2: Creating polygon')

		# Attributes
		self.verts = verts
		# If it's not an array, make it be
		try:
			verts.shape
		except AttributeError:
			self.verts = np.array(verts)
		self.nverts = len(verts)
		self.x, self.y = self.verts.T
		# Compute attributes
		self.set_segments()
		self.set_angles()
		self.get_area()
		# self.get_centroid()
		self.get_circumcircle()
		# planar.Polygon. I need it for planar.Polygon.contains_point
		self.plpol = pl.Polygon(self.verts.tolist())
示例#3
0
    def build(self, params):
        """
		Build the tessellation for the nerve
		"""

        # Get parameters
        # self.get_params(params)
        self.__dict__.update(params)

        mnd = self.mnd
        min_sep = self.min_sep
        rmin = self.rmin
        rmax = self.rmax
        circp_tol = self.circp_tol
        max_axs_pf = self.max_axs_pf
        numberofaxons = self.numberofaxons
        locations = self.locations
        radii = self.radii
        # models = self.models

        # Build contours
        self.build_contours()

        contour = self.contour
        contour_hd = self.contour_hd
        contour_pslg = self.contour_pslg
        contour_pslg_nerve = self.contour_pslg_nerve

        ##################################################################
        # Triangulate

        # Max. area for the triangles,
        # inverse to the minimum NAELC density
        maxarea = 1. / mnd
        # Triangulate
        # Instead, triangulate without taking the fascicles' contours
        # into account
        tri = triangle.triangulate(contour_pslg_nerve, 'a%f' % maxarea)
        tri = triangle.triangulate(contour_pslg, 'a%f' % maxarea)
        # Vertices
        tv = tri['vertices']

        self.original_points = tv.T

        ##################################################################
        # Fill fascicles

        # If the axons have fixed locations, get their locations and
        # radii first, and then they will be added to the different
        # fascicles when needed
        if self.packing_type == "fixed locations":
            try:
                xx_, yy_ = np.array(locations).T
            except ValueError:
                # Something went wrong or simply there are no axons
                xx_ = yy_ = rr_ = np.array([])
            else:
                rr_ = np.array(radii)

            # Axon models
            self.models = self.models['fixed']

        # else:
        # 	# Axon models. Create them according to the proportions

        # Remove points inside the fascicles
        remove_these = []
        axons = {}
        naxons = {}
        naxons_total = 0
        print('about to fill the contours')
        for k, v in contour.items():
            varr = np.array(v)
            # Remove points outside the nerve
            if 'Nerve' in k:
                plpol = pl.Polygon(v)
                for i, p in enumerate(tv):
                    # Remove any points in tv falling outside the nerve
                    # and outside its boundaries
                    # Note: that means that I don't remove the points ON the
                    # boundaries
                    if not (plpol.contains_point(p) or np.isin(p, varr).all()):
                        remove_these.append(i)
            # Remove points from the fascicles
            if 'Fascicle' in k:
                print(k)
                plpol = pl.Polygon(v)
                for i, p in enumerate(tv):
                    # Remove the points of the fascicle's contours from tv
                    inclc = plpol.contains_point(p) and (not np.isin(
                        p, varr).all())
                    # Actually, don't remove the fascicle's contours
                    # Remove any points in tv contained in a fascicle
                    notic = plpol.contains_point(p) or np.isin(p, varr).all()
                    if notic:
                        remove_these.append(i)
                # Fill the fascicle
                # Dictionary of axons
                axons[k] = {}
                # Create the circles
                # Different packing strategies yield different results
                if self.packing_type == "uniform":
                    xx, yy, rr = cp.fill(contour_hd[k],
                                         rmin,
                                         rmax,
                                         min_sep,
                                         nmaxpf=max_axs_pf,
                                         tolerance=circp_tol)
                elif self.packing_type == "gamma":
                    distr_params = {
                        "mean": self.avg_r,
                        "shape": self.gamma_shape
                    }
                    xx, yy, rr = cp.fill(contour_hd[k],
                                         rmin,
                                         rmax,
                                         min_sep,
                                         nmaxpf=max_axs_pf,
                                         tolerance=circp_tol,
                                         distribution="gamma",
                                         distr_params=distr_params)
                    print('Filled %s' % k)
                elif self.packing_type == "fixed locations":
                    # Iterate over axons and get those inside
                    # the fascicle
                    xx, yy, rr = [], [], []
                    for x_, y_, r_ in zip(xx_, yy_, rr_):
                        if plpol.contains_point((x_, y_)):
                            xx.append(x_)
                            yy.append(y_)
                            rr.append(r_)
                    xx = np.array(xx)
                    yy = np.array(yy)
                    rr = np.array(rr)

                # Store information in a clean way
                axons[k]['x'] = xx
                axons[k]['y'] = yy
                axons[k]['r'] = rr
                # axons[k]['models'] = models[:]
                naxons[k] = len(xx)
                naxons_total += naxons[k]

        rps = tv[remove_these]

        self.removed_points = rps

        keep_these = np.array(
            list(set(range(tv.shape[0])) - set(remove_these)))
        # print("keep_these:", keep_these)
        # print("remove_these:", remove_these)
        tv = tv[keep_these]

        # List x, y and r once some points have been removed
        tv = tv.T
        x, y = tv
        nc = x.size
        r = np.zeros_like(x)

        # Dictionaries for:
        # cables (their type)

        cables = OrderedDict()
        models = {}

        # Points corresponding to epineurium
        for ic in range(nc):
            cables[ic] = 'NAELC'
            # NAELC model indexing
            models[ic] = 'NAELC'
            print(ic, models, self.models)

        # Add axons to the existing points for the nerve
        for k in axons:
            x = np.array(x.tolist() + axons[k]['x'].tolist())
            y = np.array(y.tolist() + axons[k]['y'].tolist())
            r = np.array(r.tolist() + axons[k]['r'].tolist())

        nc = x.size
        nNAELC = nc - naxons_total

        # Axon models
        if self.packing_type != 'fixed locations':
            # Now that the axons have been placed, determine their models according to the proportions
            # ninst: 'number of instances' (of each model)
            ninst = {}
            proportions = self.models['proportions']
            keys = list(proportions.keys())
            for m, p in proportions.items():
                ninst[m] = int(p * naxons_total)
            # Remainder
            rem = naxons_total - sum(list(ninst.values()))

            # Just add the remaining in an arbitrary (not random) way
            for i in range(rem):
                ninst[keys[i]] += 1

            # Now select the indices of the axons for each model
            axon_indices = (np.arange(naxons_total) + nNAELC).tolist()
            remaining_axon_indices = axon_indices[:]
            # Dictionary for the axon indices for each model
            inds = {}
            # Dictionary for the model names for each index
            model_by_index = {}
            for m, p in proportions.items():
                sample = random.sample(remaining_axon_indices, ninst[m])
                remaining_axon_indices = list(
                    set(remaining_axon_indices) - set(sample))
                inds[m] = sample[:]
                for i in sample:
                    model_by_index[i] = m

        # Points corresponding to axons
        for ik, i in enumerate(np.arange(nNAELC, nc, 1)):
            cables[i] = 'Axon'
            # Axon model indexing
            if self.packing_type == 'fixed locations':
                models[i] = self.models[ik]
            else:
                models[i] = model_by_index[i]
            print(ik, i, models, self.models)

        ##################################################################
        # Power diagram
        # Zero-valued radii: Voronoi diagram

        # Build power diagram
        pd = tess.PowerDiagram(x, y, r, contour_pslg_nerve)
        pd.build()

        # Lengths of the segments and the connections
        pdpairs = pd.pairs
        pdsegments = pd.segments
        pairs = []
        segments = {}
        len_seg = {}
        len_con = {}
        for pair in pdpairs:
            # if len(pdsegments[pair]) > 1:
            if pdsegments[pair] is not None:
                seg = pdsegments[pair]
                pairs.append(pair)
                segments[pair] = seg
                a, b = seg.a, seg.b
                len_seg[pair] = geo.dist(a, b).mean()
                i, j = pair
                len_con[pair] = geo.dist((x[i], y[i]), (x[j], y[j]))

        # Store relevant stuff in the attributes
        self.pd = pd
        self.x = x
        self.y = y
        self.r = r
        self.nc = nc
        self.axons_dict = axons
        self.pairs = pairs
        self.cables = cables
        self.models = models
        # Unique list of models
        self.models_set = set(self.models.values())
        self.segments = segments
        self.trios = pd.trios
        self.len_con = len_con
        self.len_seg = len_seg
        self.free_areas = pd.free_areas
        self.circ_areas = pd.circ_areas
        # Total endoneurial cross-sectional free area
        self.endo_free_cs_area = self.fas_total_area - self.circ_areas.sum()
        self.naxons = naxons
        self.naxons_total = naxons_total
        self.nNAELC = nNAELC
示例#4
0
def fill(contour,
         rmin=0.,
         rmax=1.e99,
         min_sep=0.,
         nmaxpf=None,
         tolerance=1e4,
         tol_ta=1,
         distribution="uniform",
         distr_params=None):

    # In case it's not an array:
    try:
        _ = contour.size
    except:
        contour = np.array(contour)

    # Polygon
    pts = [tuple(item) for item in contour.tolist()]
    polygon = pl.Polygon(pts)
    center = (contour[:-1, 0].mean(), contour[:-1, 1].mean())
    diameter = 2 * np.hypot(contour[:-1, 0] - center[0],
                            contour[:-1, 1] - center[1]).max()
    radius = 0.5 * diameter

    # List of fibers

    rlist = []
    positions = []

    tryanother = 0
    nonstop = True
    # Cell counter
    cc = 0

    # minsep = min_sep * 0.5

    while nonstop:
        # Random radius
        if distribution == "uniform":
            r = np.random.uniform(rmin, rmax, 1)
        elif distribution == "gamma":
            valid = False
            while not valid:
                # Work with diameters first, then back to radius
                mean = 2. * distr_params["mean"]
                shape = distr_params["shape"]
                scale = mean / shape
                r = 0.5 * np.random.gamma(shape, scale, 1)
                valid = (r >= rmin) & (r <= rmax)

        allowed_r = r + min_sep
        # Go trying different positions
        k = 0
        while (k < tolerance):
            # Random position inside the polygon
            correct = False
            while not correct:
                # Try a random position
                dx = np.random.uniform(-radius, -radius + diameter)
                dy = np.random.uniform(-radius, -radius + diameter)
                x = center[0] + dx
                y = center[1] + dy
                # 1: Check if the center is inside the polygon
                correct = polygon.contains_point((x, y))
                # 2: Check that the whole fiber is inside the polygon
                # For this, I actually check that all the points of the
                # polygon are farther than the fiber radius
                cx, cy = contour[:, 0], contour[:, 1]
                correct = correct & (np.hypot(cx - x, cy - y) >
                                     allowed_r).all()
                k += 1

            # Check for clashes with other existing sub-units
            clash = False
            for i, xy in enumerate(positions):
                xc, yc = xy
                if (np.hypot(x - xc, y - yc) < allowed_r + rlist[i]):
                    # Clash. This sub-unit doesn't fit here
                    clash = True
                    break

            if clash:
                k += 1
                # If I tried too many times with a sub-unit and it
                # didn't fit, stop
                if k >= tolerance:
                    tryanother += 1
                    if tryanother >= tol_ta:
                        nonstop = False
                # Else, keep trying
            else:
                # No clash at all. Good position
                xy = (x, y)
                positions.append(xy)
                rlist.append(r)
                cc += 1
                k = tolerance
                if cc >= nmaxpf:
                    nonstop = False

    positions, rlist = np.array(positions), np.array(rlist)
    r = rlist[..., 0]
    x, y = positions.T
    return x, y, r