Finds groups of halfspace plane equations that are within a certain angular and linear deviation, computes the average and construct a mapping from original to cluster average.
(self, data)
| 681 | |
| 682 | @utils.trace |
| 683 | def create_mapping(self, data): |
| 684 | """Finds groups of halfspace plane equations that are within a certain |
| 685 | angular and linear deviation, computes the average and construct a |
| 686 | mapping from original to cluster average. |
| 687 | """ |
| 688 | |
| 689 | if self.settings.verbose and self.settings.debug: |
| 690 | for ii, eqs in enumerate(data.non_convex_halfspace_facets_equations): |
| 691 | print('ELEMENT', ii) |
| 692 | for i, eq in enumerate(eqs): |
| 693 | print(i, *to_str(eq)) |
| 694 | |
| 695 | epeck_equation_list_idx = numpy.cumsum([0] + list(map(len, data.epeck_equation_idxs))) |
| 696 | # epeck_equation_idxs_flat = list(itertools.chain.from_iterable(data.epeck_equation_idxs)) |
| 697 | |
| 698 | mapping = [] |
| 699 | |
| 700 | # First use a kd-tree to find planes with similar normals (the first three) components |
| 701 | # of the plane equations. Note that we search also for the opposite. |
| 702 | |
| 703 | # A single float64 vector might be associated to multiple distinct epeck equations. |
| 704 | # in our kd-tree we store unique float64 coordinates and maintain a mapping back to |
| 705 | # indices into the original epeck equations. |
| 706 | |
| 707 | vecs = numpy.concatenate(data.float_facet_normals) |
| 708 | vecs_unique, vecs_inverse = numpy.unique(vecs, return_inverse=True, axis=0) |
| 709 | vecs_dict = utils.make_default(sorted((j, i) for i, j in enumerate(vecs_inverse))) |
| 710 | |
| 711 | points = numpy.concatenate(data.float_facet_centroids) |
| 712 | kdtree = KDTree(vecs_unique) |
| 713 | |
| 714 | G = graph.Graph() |
| 715 | |
| 716 | if has_igraph: |
| 717 | # @todo write a proper adaptor. igraph only supports integer vertex ids, so we |
| 718 | # need a separate mapping |
| 719 | # vertices = [(+1, i) for i in range(len(vecs_unique))] + [(-1, i) for i in range(len(vecs_unique))] |
| 720 | G.add_vertices(len(vecs_unique)) |
| 721 | vidx = lambda x: x |
| 722 | getv = lambda x: x |
| 723 | add_edges = lambda g, es: g.add_edges(es) |
| 724 | components = lambda g: list(g.connected_components()) |
| 725 | else: |
| 726 | vidx = lambda x: x |
| 727 | getv = lambda x: x |
| 728 | add_edges = lambda g, es: g.add_edges_from(es) |
| 729 | components = lambda g: list(graph.connected_components(g)) |
| 730 | |
| 731 | def yield_edges(): |
| 732 | for i, p in enumerate(vecs_unique): |
| 733 | # @todo if i in G.nodes: continue? |
| 734 | for sign in (+1, -1): |
| 735 | yield from ((i,j) for j in kdtree.query_ball_point(p * sign, r=0.2)) |
| 736 | # for i in range(len(vecs_unique)): |
| 737 | # yield (vidx((+1, i)), vidx((-1, i))) |
| 738 | |
| 739 | add_edges(G, yield_edges()) |
| 740 |