Example #1
0
    def test_parallel_segments_must_be_1_5_4_5_and_1_1_4_1_for_1_3_4_3_at_2_distance(
            self):
        segment = geometry.Segment(1, 3, 4, 3)

        s1, s2 = segment.parallel_segments(2)

        self.assertEqual((s1._x1, s1._y1, s1._x2, s1._y2), (1, 5, 4, 5))
        self.assertEqual((s2._x1, s2._y1, s2._x2, s2._y2), (1, 1, 4, 1))
Example #2
0
def build_laguerre(gc, trios):
    """ Build the Laguerre diagram from a cloud of points and its given 
	triangulation """

    # Update the triangulation
    gc.update_triangulation(trios)
    trios = gc.trios

    # Lines connecting centers
    lcc = LinesConnectingCenters(gc)
    lcc.build()
    # Power lines
    pl = PowerLines(gc, lcc)
    pl.build()

    # Possible Vertices (PV)
    # Intersections among power lines
    xi, yi = geo.intersections_many_lines([pl])
    lpairs, xi = alg.one_side(xi)
    lpairs, yi = alg.one_side(yi)
    # Determine the group of circles for each possible vertex
    pvnc = len(yi)
    gcpvc = pl.pairs[lpairs]
    gcpvc = gcpvc.reshape((pvnc, 4))
    gcpvc = np.sort(gcpvc)
    lgp = np.array(list(map(lambda l: len(set(l)), gcpvc)))
    keep_these = np.where(lgp == 3)
    xi = xi[keep_these]
    yi = yi[keep_these]
    lpairs = lpairs[keep_these]
    gcpvc = gcpvc[keep_these]
    pvnc = len(xi)
    gcpvc = np.array(list(map(lambda l: sorted(list(set(l))), gcpvc)))
    # Now I have to iterate over trios
    # Coordinates of the possible vertex for each triangle
    xpv = {}
    ypv = {}
    # Segment for each pair
    segments = {}
    # Number of PV points for each pair
    pvpts = {}
    # One (if the pair is on the boundary) or two trios per pair
    pairs_trios = {}
    # Other pairs of the quad whose diagonal is a certain pair
    pairs_oprs = {}
    # Other points of the quad whose diagonal is a certain pair
    pairs_opts = {}
    # All points of the quad whose diagonal is a certain pair
    pairs_allpts = {}
    # Iterate
    for trio in trios:
        trio_extended = np.tile(trio, pvnc).reshape(gcpvc.shape)
        matches = np.equal(gcpvc, trio_extended)
        matches = np.all(matches, axis=1)
        matches = np.where(matches == True)[0]
        matches = np.unique(matches)
        xim = xi[matches]
        yim = yi[matches]

        # Now reduce the duplicated points for this triangle
        if len(xim) > 1:
            xim, yim = remove_repeated_points(xim, yim)

        # Store them
        if len(xim) > 0:
            tt = tuple(trio)

            xim, yim = xim.mean(), yim.mean()

            pairs_sorted = [
                tuple(sorted(item)) for item in gc.triangles[tt].pairs
            ]

            # Pairs
            for pair in pairs_sorted:
                other_pairs = [item for item in pairs_sorted if item != pair]
                try:
                    segments[pair].append((xim, yim))
                    pvpts[pair] += 1
                except KeyError:
                    segments[pair] = [(xim, yim)]
                    pvpts[pair] = 1
                    # For this pair, store the trio and the other pairs
                    pairs_trios[pair] = [tt]
                    pairs_oprs[pair] = other_pairs
                else:
                    pairs_trios[pair].append(tt)
                    pairs_oprs[pair] = pairs_oprs[pair] + other_pairs
                pa = set(np.array(pairs_oprs[pair]).flatten().tolist() \
                       + list(pair))
                pairs_allpts[pair] = list(pa)
                pairs_opts[pair] = sorted(list(pa - set(pair)))

    # List pairs
    pairs = list(pairs_oprs.keys())

    # for k, v in pvpts.items():
    # 	print(k, v)

    # Get far points
    segments = get_far_points(gc, segments, pvpts, pl.lines)

    # Update segments dictionary
    for k, seg in segments.items():
        # if len(seg) != 2:
        if not isinstance(seg, geo.Segment):
            if len(seg) < 2:
                segments[k] = seg
                # pass
            if len(seg) == 2:
                segments[k] = geo.Segment(seg)
    # Return
    return pairs, trios, segments, pairs_trios, pairs_oprs, pairs_opts, pairs_allpts, pvpts, pl.lines
Example #3
0
    def build(self):
        """
		Build it
		"""

        ws.log("Building the power diagram")

        x, y, r = self.x, self.y, self.r
        # Generating circles
        gc = GCircles(x, y, r)
        gc.triangulate()

        # First iteration
        pairs, trios, segments, pairs_trios, pairs_oprs, pairs_opts, \
         pairs_allpts, pvpts, lines = build_laguerre(gc, gc.trios)
        # First correction
        new_trios, new_pairs, rmv_trios, rmv_pairs, finished = \
         one_correction(pairs_oprs, pairs_opts, pairs_trios, segments)
        trios = update_trios(new_trios, rmv_trios, trios)
        # Iterate until there's no more bad crossings
        # Iteration counter
        corrcount = 0
        while not finished:
            pairs, trios, segments, pairs_trios, pairs_oprs, pairs_opts, \
             pairs_allpts, pvpts, lines = build_laguerre(gc, trios)
            new_trios, new_pairs, rmv_trios, rmv_pairs, finished = \
             one_correction(pairs_oprs, pairs_opts, pairs_trios, segments)
            trios = update_trios(new_trios, rmv_trios, trios)
            # Go fix the only-two-connections issue
            poss_lost = []
            poss_lost, rmv_trios, new_trios = fix_biconnections(
                poss_lost, pairs, gc, pairs_trios)
            if len(poss_lost) > 0:
                trios = update_trios(new_trios, rmv_trios, trios)
                pairs, trios, segments, pairs_trios, pairs_oprs, pairs_opts, \
                 pairs_allpts, pvpts, lines = build_laguerre(gc, trios)
                # 'This should be fixed now'
                whoslost = poss_lost[0]
            corrcount += 1
            enough = corrcount == gc.nc / 4

            # Check if this is finished
            finished = finished or enough
            ws.log('Number of corrections: %i' % corrcount)
            if enough:
                error_msg = 'TESSELLATION ERROR: Something went ' \
                 + 'wrong with this set of circles\n'\
                 + 'This is probably due to a bug in the algorithm\n' \
                 + 'Please try a different set of circles\n'
                ws.log(error_msg)
                self.any_errors = True
                print('TESSELLATION ERROR')
                return
        ws.log('Correction iterations: %i' % corrcount)

        # Check if two connections cross
        for ip, pair1 in enumerate(pairs):
            a = segments[pair1]
            for pair2 in pairs[ip + 1:]:
                b = segments[pair2]
                if isinstance(a, geo.Segment) and isinstance(b, geo.Segment):
                    crossing, _ = geo.crossing_segments(a, b)
                    overlapping = geo.overlapping_segments(a, b)
                    if crossing or overlapping:
                        ws.log(
                            'TESSELLATION ERROR: An error was found for pairs: %s, %s'
                            % (str(pair1), str(pair2)))
                        ws.log('This is due to a bug in the algorithm')
                        ws.log('Please try a different set of circles')
                        self.any_errors = True
                        print('TESSELLATION ERROR')
                        return
                else:
                    pass

        # If finished, crop the diagram using the contour
        if self.contour is not None:

            # print('')
            # print('segments:')
            # for k, v in segments.items():
            # 	print(k, v)

            # Crop it
            segments = crop_diagram(gc, pairs, segments, pvpts, lines,
                                    self.contour)

        # Finally, remove the segments which are not geo.Segment
        # instances
        for k, seg in segments.items():
            if not isinstance(seg, geo.Segment):
                if len(seg) != 2:
                    segments[k] = None
                if len(seg) == 2:
                    segments[k] = geo.Segment(seg)

        self.pairs = pairs
        self.segments = segments
        self.trios = trios

        self.get_polygons()
Example #4
0
points = generator.points
segments = generator.segments
for point_ in points:
    point = geometry.Point(1, 1)
    point.y = -point_[0].y
    point.x = point_[0].x
    symbol = point_[1]
    canvas.create_oval(x0 + point.x, y0 + point.y, x0 + point.x, y0 + point.y)
    canvas.create_text(x0 + point.x,
                       y0 + point.y - 8,
                       text=symbol,
                       font='Arial 8',
                       fill='darkblue')
for segment in segments:
    once_segment = [
        geometry.Segment(geometry.Point(0, 0), geometry.Point(0, 0)), '00'
    ]
    once_segment[0].A.y = -segment[0].A.y
    once_segment[0].B.y = -segment[0].B.y
    once_segment[0].A.x = segment[0].A.x
    once_segment[0].B.x = segment[0].B.x
    once_segment[1] = segment[1]
    canvas.create_line(x0 + once_segment[0].A.x,
                       y0 + once_segment[0].A.y,
                       x0 + once_segment[0].B.x,
                       y0 + once_segment[0].B.y,
                       fill='#' + segment[1][:2] + segment[1][1] +
                       segment[1][-2] + segment[1][-2:])
canvas.pack()
root.mainloop()
Example #5
0
 def test_angle_must_be_0_for_1_1_1_3(self):
     segment = geometry.Segment(1, 1, 1, 3)
     self.assertEqual(segment.angle, 0)
Example #6
0
 def test_angle_must_be_90_for_1_1_3_1(self):
     segment = geometry.Segment(1, 1, 3, 1)
     self.assertEqual(segment.angle, 90)
Example #7
0
 def test_length_must_equal_5_for_345_triangle(self):
     hypotenuse = geometry.Segment(3, 4, 6, 8)
     self.assertEqual(hypotenuse.length, 5)
Example #8
0
    def build_from_json(self):
        """
		Build the nerve using the parameters stored in json files
		"""

        # Build contours
        self.c_reduction = ws.anatomy_settings["cross-section"][
            "contours point reduction"]
        self.build_contours()

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

        # Build internal elements
        x = []
        y = []
        r = []
        cables = OrderedDict()
        free_areas = []
        start_positions = []
        cables_tissues = OrderedDict()
        segments = {}
        len_seg = {}
        len_con = {}
        numberof = {'Axon': 0, 'NAELC': 0}
        models = {}

        itpath = ws.anatomy_settings["cross-section"]["internal topology file"]
        topology = read_from_json(itpath, object_pairs_hook=OrderedDict)

        # Read the dictionary and crete the necessary variables from it

        for i, c in topology['cables'].items():
            i = int(i)
            cables[i] = c['type']
            x.append(c['x'])
            y.append(c['y'])
            r.append(c['r'])
            free_areas.append(c['free extracellular area'])
            start_positions.append(c['start position'])
            cables_tissues[i] = OrderedDict()
            cables_tissues[i]['endoneurium'] = c['endoneurium']
            cables_tissues[i]['epineurium'] = c['epineurium']
            numberof[c['type']] += 1
            # Axon model
            try:
                models[i] = c['model']
            except KeyError:
                # It's not an axon
                models[i] = cables[i]

        # Turn the cables dictionary into a sorted list
        # And also sort everything else
        sortorder = np.argsort(np.array(list(cables.keys())))
        cables = np.array(list(cables.values()))[sortorder]
        x = np.array(x)[sortorder]
        y = np.array(y)[sortorder]
        r = np.array(r)[sortorder]
        free_areas = np.array(free_areas)[sortorder]
        start_positions = np.array(start_positions)[sortorder]

        # Now pairs...
        for p in topology['pairs'].values():
            i, j = p['pair']
            pair = (i, j)
            s = p['separator segment']
            a = s['a']
            b = s['b']
            seg = geo.Segment(((a['x'], a['y']), (b['x'], b['y'])))
            segments[pair] = seg
            len_seg[pair] = seg.length
            len_con[pair] = geo.dist((x[i], y[i]), (x[j], y[j]))

        # Save things as attributes
        # self.x = np.array(x)
        # self.y = np.array(y)
        # self.r = np.array(r)
        # self.free_areas = np.array(free_areas)
        # self.start_positions = np.array(start_positions)
        self.x = x
        self.y = y
        self.r = r
        self.free_areas = free_areas
        self.start_positions = start_positions
        self.cables_tissues = cables_tissues
        self.segments = segments
        self.len_seg = len_seg
        self.len_con = len_con
        self.pairs = len_con.keys()
        self.cables = cables
        self.models = models
        # Unique list of models
        self.models_set = set(self.models.values())
        # print('cables:', cables)
        # print('r:', r)
        # for c_, r_ in zip(cables, r):
        # 	print(c_, r_)
        self.nc = len(cables)
        self.naxons_total = numberof['Axon']
        self.nNAELC = numberof['NAELC']
        # Build power diagram
        pd = tess.PowerDiagram(self.x, self.y, self.r, contour_pslg_nerve)
        # for p, s in zip(self.pairs, self.segments.values()):
        # 	print(p, str(s))
        pd.build_preexisting(self.pairs, self.segments)
        self.trios = pd.trios
        self.pd = pd
        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()
Example #9
0
 def test_line_line_no_segment(self):
     # No segment intersect, but lines do
     a = geometry.Segment((2, 1), (4, 2))
     b = geometry.Segment((0, 1), (2, 0))
     self.assertEqual(geometry.line_intersect(a.p0, a.p1, b.p0, b.p1),
                      (1, 0.5))
Example #10
0
 def test_segment_line_parallel(self):
     # Parallel segments
     a = geometry.Segment((0, 0), (4, 2))
     b = geometry.Segment((1, 0), (3, 1))
     self.assertEqual(a.intersect_segment(b), None)
Example #11
0
 def test_line_line(self):
     # No segment intersect, but lines do
     a = geometry.Segment((2, 1), (4, 2))
     b = geometry.Segment((0, 1), (2, 0))
     self.assertEqual(a.intersect_segment(b), None)
Example #12
0
 def test_segment_line_105(self):
     # Intersecting at (1, 0.5)
     a = geometry.Segment((0, 0), (4, 2))
     b = geometry.Segment((2, 0), (0, 1))
     self.assertEqual(a.intersect_segment(b), (1, 0.5))
Example #13
0
 def test_segment_line_21(self):
     # Intersecting at (2, 1)
     a = geometry.Segment((0, 0), (4, 2))
     b = geometry.Segment((0, 3), (3, 0))
     self.assertEqual(a.intersect_segment(b), (2, 1))
Example #14
0
def get_far_points(gc, segments, pvpts, lines):
    """
	Get the points being far away
	"""

    # Pairs that only have one point (on the boundary)
    iwhobdr = np.where(np.array(list(pvpts.values())) == 1)
    whobdr = np.array(list(pvpts.keys()))[iwhobdr]
    # Give them a second point very far away
    # Calculate limits
    xmin, xmax = gc.x.min(), gc.x.max()
    ymin, ymax = gc.y.min(), gc.y.max()
    dx = xmax - xmin
    dy = ymax - ymin
    xfar_left = xmin - 1e3 * dx
    xfar_rght = xmax + 1e3 * dx
    yfar_bot = ymin - 1e3 * dy
    yfar_top = ymax + 1e3 * dy

    for pair in whobdr:
        # Format the pair to amke it a tuple
        pair = tuple(pair.tolist())
        # Get point and clean it
        try:
            point = tuple([float(x) for x in segments[pair][0]])
        except TypeError:
            point = segments[pair].a
        if point is not None:

            powl = lines[pair]

            # If it's a vertical line, do it differently
            slope = powl.slope
            vline = (slope == np.inf) or (slope
                                          == -np.inf) or (np.isnan(slope))

            if vline:
                xfar = point[0]
                ypnt = point[1]
                farpt_up = geo.Segment([(xfar, ypnt), (xfar, yfar_top)])
                farpt_dn = geo.Segment([(xfar, ypnt), (xfar, yfar_bot)])
                possible_segs = [farpt_dn, farpt_up]
            else:

                yfar_left = powl.equation(xfar_left)
                yfar_rght = powl.equation(xfar_rght)

                # Only one of the segments does not intersect with any other
                sleft = geo.Segment([point, (xfar_left, yfar_left)])
                srght = geo.Segment([point, (xfar_rght, yfar_rght)])
                possible_segs = [sleft, srght]

            # Try the left-hand segment and see if that's the good one
            valid_segment = np.array([False, False])
            for i, tryseg in enumerate(possible_segs):
                this_one_not_valid = False
                for othpair, othseg in segments.items():
                    if (pair != othpair) and isinstance(othseg, geo.Segment):
                        crossing, crosspoint = geo.crossing_segments(
                            tryseg, othseg)
                        overlapping = geo.overlapping_segments(tryseg, othseg)
                        this_one_not_valid = crossing or overlapping
                        if this_one_not_valid:
                            # Not this one
                            break
                if not this_one_not_valid:
                    valid_segment[i] = True

            if (valid_segment == True).all():
                # Choose the shortest one
                s0 = possible_segs[0]
                s1 = possible_segs[1]
                if s0.length < s1.length:
                    segments[pair] = s0
                else:
                    segments[pair] = s1
            elif (valid_segment == True).any():
                segments[pair] = possible_segs[np.where(
                    valid_segment == True)[0][0]]
            else:
                print('No far point could be given to:', pair)

    return segments
Example #15
0
 def test_center_must_be_3_4_for_0_0_6_8(self):
     hypotenuse = geometry.Segment(0, 0, 6, 8)
     self.assertEqual(hypotenuse.center, (3, 4))
Example #16
0
def one_correction(pairs_oprs, pairs_opts, pairs_trios, segments):
    """ Perform one single trio change """

    # New trios
    new_trios = []
    # New pairs
    new_pairs = []

    # Removed trios
    rmv_trios = []
    # Removed pairs
    rmv_pairs = []

    # Iterate over pairs to check crossing segments
    pairs = list(pairs_trios.keys())[:]
    for pair in pairs:
        other_pairs = pairs_oprs[pair]
        for i, op1 in enumerate(other_pairs):
            a = segments[op1]
            for op2 in other_pairs[i + 1:]:
                b = segments[op2]
                # if (len(a) == 2) & (len(b) == 2):
                # if True:
                if isinstance(a, geo.Segment) and isinstance(b, geo.Segment):
                    crossing, _ = geo.crossing_segments(a, b)
                    if crossing:
                        # Change the connection: use the other diagonal of the
                        # quad
                        # Remove bad pair
                        rmv_pairs.append(pair)
                        # Update with new pair
                        new_pair = tuple(pairs_opts[pair])
                        new_pairs.append(new_pair)

                        # Update its segment
                        xyint = geo.intersection_segments(a, b)
                        try:
                            isgeoSeg = isinstance(segments[new_pair],
                                                  geo.Segment)
                        except KeyError:
                            segments = tools.append_items(
                                segments, new_pair, [xyint])
                        else:
                            if not isgeoSeg:
                                segments = tools.append_items(
                                    segments, new_pair, [xyint])
                        # if not isinstance(segments[new_pair], geo.Segment):
                        # try:
                        #	segments[new_pair].append(xyint)
                        # except KeyError:
                        #	segments[new_pair] = [xyint]

                        # Update the trios
                        # Remove bad trios
                        for trio in pairs_trios[pair]:
                            rmv_trios.append(trio)
                        # Update with new trios
                        for p in pair:
                            new_trio = tuple(sorted(list(new_pair) + [p]))
                            new_trios.append(new_trio)

                        # Update segments dictionary
                        for k, seg in segments.items():
                            if not isinstance(seg, geo.Segment):
                                # if len(seg) != 2:
                                if len(seg) < 2:
                                    segments[k] = seg
                                if len(seg) == 2:
                                    segments[k] = geo.Segment(seg)

                        # The important thing here
                        return new_trios, new_pairs, rmv_trios, rmv_pairs, False

    return new_trios, new_pairs, rmv_trios, rmv_pairs, True
Example #17
0
    def build_preexisting(self):
        """
		Build the nerve using the parameters stored in files
		"""

        # Build contours
        self.c_reduction = ws.anatomy_settings["cross-section"][
            "contours point reduction"]
        self.build_contours()

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

        # Build internal elements
        x = []
        y = []
        r = []
        cables = []
        free_areas = []
        start_positions = []
        cables_tissues = OrderedDict()
        segments = {}
        len_seg = {}
        len_con = {}
        numberof = {'Axon': 0, 'NAELC': 0}
        itpath = ws.anatomy_settings["cross-section"]["internal topology file"]
        with open(itpath, 'r') as f:
            # Skip header
            frl = list(csv.reader(f, delimiter=';'))[1:]
            # k is a cable counter
            k = 0
            for row in frl:
                key = row[0]
                if key != 'Pair':
                    cables.append(key)
                    x.append(float(row[1]))
                    y.append(float(row[2]))
                    r.append(float(row[3]))
                    free_areas.append(float(row[4]))
                    start_positions.append(float(row[5]))
                    try:
                        cables_tissues[k] = {
                            'epineurium': float(row[7]),
                            'endoneurium': float(row[6])
                        }
                    except IndexError:
                        # There's no such information
                        cables_tissues[k] = {
                            'epineurium': 0.,
                            'endoneurium': 0.
                        }
                    numberof[key] += 1
                    k += 1
                else:
                    i = int(row[1])
                    j = int(row[2])
                    segments[(i, j)] = geo.Segment([
                        (float(row[3]), float(row[4])),
                        (float(row[5]), float(row[6]))
                    ])
                    len_seg[(i, j)] = float(row[7])
                    len_con[(i, j)] = float(row[8])

        # Save things as attributes

        self.x = np.array(x)
        self.y = np.array(y)
        self.r = np.array(r)
        self.free_areas = np.array(free_areas)
        self.start_positions = np.array(start_positions)
        self.cables_tissues = cables_tissues
        self.segments = segments
        self.len_seg = len_seg
        self.len_con = len_con
        self.pairs = len_con.keys()
        self.cables = cables
        self.nc = len(cables)
        self.naxons_total = numberof['Axon']
        self.nNAELC = numberof['NAELC']
        # Build power diagram
        pd = tess.PowerDiagram(self.x, self.y, self.r, contour_pslg_nerve)
        for p, s in zip(self.pairs, self.segments.values()):
            print(p, str(s))
        pd.build_preexisting(self.pairs, self.segments)
        self.trios = pd.trios
        self.pd = pd
        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()