# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
import collections
UNKNOWN = np.nan
R = 1
FR = 2
F = 3
FL = 4
L = 5
BL = 6
B = 7
BR = 8
U = 9
UF = 10
UB = 11
UL = 12
UR = 13
UFL = 14
UFR = 15
UBL = 16
UBR = 17
D = 18
DF = 19
DB = 20
DL = 21
DR = 22
DFL = 23
DFR = 24
DBL = 25
DBR = 26
INT_TO_CODE = collections.OrderedDict(
[
(UNKNOWN, 'unknown'),
(R, 'right'),
(FR, 'frontright'),
(F, 'front'),
(FL, 'frontleft'),
(L, 'left'),
(BL, 'backleft'),
(B, 'back'),
(BR, 'backright'),
(U, 'up'),
(UF, 'upfront'),
(UB, 'upback'),
(UL, 'upleft'),
(UR, 'upright'),
(UFL, 'upfrontleft'),
(UFR, 'upfrontright'),
(UBL, 'upbackleft'),
(UBR, 'upbackright'),
(D, 'down'),
(DF, 'downfront'),
(DB, 'downback'),
(DL, 'downleft'),
(DR, 'downright'),
(DFL, 'downfrontleft'),
(DFR, 'downfrontright'),
(DBL, 'downbackleft'),
(DBR, 'downbackright'),
]
)
# HACK: mirrors ibeis viewpoint int distance encoding
VIEW_INT_DIST = {
# DIST 0 PAIRS
(B, B): 0,
(BL, BL): 0,
(BR, BR): 0,
(D, D): 0,
(DB, DB): 0,
(DBL, DBL): 0,
(DBR, DBR): 0,
(DF, DF): 0,
(DFL, DFL): 0,
(DFR, DFR): 0,
(DL, DL): 0,
(DR, DR): 0,
(F, F): 0,
(FL, FL): 0,
(FR, FR): 0,
(L, L): 0,
(R, R): 0,
(U, U): 0,
(UB, UB): 0,
(UBL, UBL): 0,
(UBR, UBR): 0,
(UF, UF): 0,
(UFL, UFL): 0,
(UFR, UFR): 0,
(UL, UL): 0,
(UR, UR): 0,
# DIST 1 PAIRS
(B, BL): 1,
(B, BR): 1,
(B, DB): 1,
(B, DBL): 1,
(B, DBR): 1,
(B, UB): 1,
(B, UBL): 1,
(B, UBR): 1,
(BL, DBL): 1,
(BL, L): 1,
(BL, UBL): 1,
(BR, DBR): 1,
(BR, R): 1,
(BR, UBR): 1,
(D, DB): 1,
(D, DBL): 1,
(D, DBR): 1,
(D, DF): 1,
(D, DFL): 1,
(D, DFR): 1,
(D, DL): 1,
(D, DR): 1,
(DB, DBL): 1,
(DB, DBR): 1,
(DBL, DL): 1,
(DBL, L): 1,
(DBR, DR): 1,
(DBR, R): 1,
(DF, DFL): 1,
(DF, DFR): 1,
(DF, F): 1,
(DFL, DL): 1,
(DFL, F): 1,
(DFL, FL): 1,
(DFL, L): 1,
(DFR, DR): 1,
(DFR, F): 1,
(DFR, FR): 1,
(DFR, R): 1,
(DL, L): 1,
(DR, R): 1,
(F, FL): 1,
(F, FR): 1,
(F, UF): 1,
(F, UFL): 1,
(F, UFR): 1,
(FL, L): 1,
(FL, UFL): 1,
(FR, R): 1,
(FR, UFR): 1,
(L, UBL): 1,
(L, UFL): 1,
(L, UL): 1,
(R, UBR): 1,
(R, UFR): 1,
(R, UR): 1,
(U, UB): 1,
(U, UBL): 1,
(U, UBR): 1,
(U, UF): 1,
(U, UFL): 1,
(U, UFR): 1,
(U, UL): 1,
(U, UR): 1,
(UB, UBL): 1,
(UB, UBR): 1,
(UBL, UL): 1,
(UBR, UR): 1,
(UF, UFL): 1,
(UF, UFR): 1,
(UFL, UL): 1,
(UFR, UR): 1,
# DIST 2 PAIRS
(B, D): 2,
(B, DL): 2,
(B, DR): 2,
(B, L): 2,
(B, R): 2,
(B, U): 2,
(B, UL): 2,
(B, UR): 2,
(BL, BR): 2,
(BL, D): 2,
(BL, DB): 2,
(BL, DBR): 2,
(BL, DFL): 2,
(BL, DL): 2,
(BL, FL): 2,
(BL, U): 2,
(BL, UB): 2,
(BL, UBR): 2,
(BL, UFL): 2,
(BL, UL): 2,
(BR, D): 2,
(BR, DB): 2,
(BR, DBL): 2,
(BR, DFR): 2,
(BR, DR): 2,
(BR, FR): 2,
(BR, U): 2,
(BR, UB): 2,
(BR, UBL): 2,
(BR, UFR): 2,
(BR, UR): 2,
(D, F): 2,
(D, FL): 2,
(D, FR): 2,
(D, L): 2,
(D, R): 2,
(DB, DF): 2,
(DB, DFL): 2,
(DB, DFR): 2,
(DB, DL): 2,
(DB, DR): 2,
(DB, L): 2,
(DB, R): 2,
(DB, UB): 2,
(DB, UBL): 2,
(DB, UBR): 2,
(DBL, DBR): 2,
(DBL, DF): 2,
(DBL, DFL): 2,
(DBL, DFR): 2,
(DBL, DR): 2,
(DBL, FL): 2,
(DBL, UB): 2,
(DBL, UBL): 2,
(DBL, UBR): 2,
(DBL, UFL): 2,
(DBL, UL): 2,
(DBR, DF): 2,
(DBR, DFL): 2,
(DBR, DFR): 2,
(DBR, DL): 2,
(DBR, FR): 2,
(DBR, UB): 2,
(DBR, UBL): 2,
(DBR, UBR): 2,
(DBR, UFR): 2,
(DBR, UR): 2,
(DF, DL): 2,
(DF, DR): 2,
(DF, FL): 2,
(DF, FR): 2,
(DF, L): 2,
(DF, R): 2,
(DF, UF): 2,
(DF, UFL): 2,
(DF, UFR): 2,
(DFL, DFR): 2,
(DFL, DR): 2,
(DFL, FR): 2,
(DFL, UBL): 2,
(DFL, UF): 2,
(DFL, UFL): 2,
(DFL, UFR): 2,
(DFL, UL): 2,
(DFR, DL): 2,
(DFR, FL): 2,
(DFR, UBR): 2,
(DFR, UF): 2,
(DFR, UFL): 2,
(DFR, UFR): 2,
(DFR, UR): 2,
(DL, DR): 2,
(DL, F): 2,
(DL, FL): 2,
(DL, UBL): 2,
(DL, UFL): 2,
(DL, UL): 2,
(DR, F): 2,
(DR, FR): 2,
(DR, UBR): 2,
(DR, UFR): 2,
(DR, UR): 2,
(F, L): 2,
(F, R): 2,
(F, U): 2,
(F, UL): 2,
(F, UR): 2,
(FL, FR): 2,
(FL, U): 2,
(FL, UBL): 2,
(FL, UF): 2,
(FL, UFR): 2,
(FL, UL): 2,
(FR, U): 2,
(FR, UBR): 2,
(FR, UF): 2,
(FR, UFL): 2,
(FR, UR): 2,
(L, U): 2,
(L, UB): 2,
(L, UF): 2,
(R, U): 2,
(R, UB): 2,
(R, UF): 2,
(UB, UF): 2,
(UB, UFL): 2,
(UB, UFR): 2,
(UB, UL): 2,
(UB, UR): 2,
(UBL, UBR): 2,
(UBL, UF): 2,
(UBL, UFL): 2,
(UBL, UFR): 2,
(UBL, UR): 2,
(UBR, UF): 2,
(UBR, UFL): 2,
(UBR, UFR): 2,
(UBR, UL): 2,
(UF, UL): 2,
(UF, UR): 2,
(UFL, UFR): 2,
(UFL, UR): 2,
(UFR, UL): 2,
(UL, UR): 2,
# DIST 3 PAIRS
(B, DF): 3,
(B, DFL): 3,
(B, DFR): 3,
(B, FL): 3,
(B, FR): 3,
(B, UF): 3,
(B, UFL): 3,
(B, UFR): 3,
(BL, DF): 3,
(BL, DFR): 3,
(BL, DR): 3,
(BL, F): 3,
(BL, R): 3,
(BL, UF): 3,
(BL, UFR): 3,
(BL, UR): 3,
(BR, DF): 3,
(BR, DFL): 3,
(BR, DL): 3,
(BR, F): 3,
(BR, L): 3,
(BR, UF): 3,
(BR, UFL): 3,
(BR, UL): 3,
(D, UB): 3,
(D, UBL): 3,
(D, UBR): 3,
(D, UF): 3,
(D, UFL): 3,
(D, UFR): 3,
(D, UL): 3,
(D, UR): 3,
(DB, F): 3,
(DB, FL): 3,
(DB, FR): 3,
(DB, U): 3,
(DB, UFL): 3,
(DB, UFR): 3,
(DB, UL): 3,
(DB, UR): 3,
(DBL, F): 3,
(DBL, FR): 3,
(DBL, R): 3,
(DBL, U): 3,
(DBL, UF): 3,
(DBL, UR): 3,
(DBR, F): 3,
(DBR, FL): 3,
(DBR, L): 3,
(DBR, U): 3,
(DBR, UF): 3,
(DBR, UL): 3,
(DF, U): 3,
(DF, UBL): 3,
(DF, UBR): 3,
(DF, UL): 3,
(DF, UR): 3,
(DFL, R): 3,
(DFL, U): 3,
(DFL, UB): 3,
(DFL, UR): 3,
(DFR, L): 3,
(DFR, U): 3,
(DFR, UB): 3,
(DFR, UL): 3,
(DL, FR): 3,
(DL, R): 3,
(DL, U): 3,
(DL, UB): 3,
(DL, UBR): 3,
(DL, UF): 3,
(DL, UFR): 3,
(DR, FL): 3,
(DR, L): 3,
(DR, U): 3,
(DR, UB): 3,
(DR, UBL): 3,
(DR, UF): 3,
(DR, UFL): 3,
(F, UB): 3,
(F, UBL): 3,
(F, UBR): 3,
(FL, R): 3,
(FL, UB): 3,
(FL, UBR): 3,
(FL, UR): 3,
(FR, L): 3,
(FR, UB): 3,
(FR, UBL): 3,
(FR, UL): 3,
(L, UBR): 3,
(L, UFR): 3,
(L, UR): 3,
(R, UBL): 3,
(R, UFL): 3,
(R, UL): 3,
# DIST 4 PAIRS
(B, F): 4,
(BL, FR): 4,
(BR, FL): 4,
(D, U): 4,
(DB, UF): 4,
(DBL, UFR): 4,
(DBR, UFL): 4,
(DF, UB): 4,
(DFL, UBR): 4,
(DFR, UBL): 4,
(DL, UR): 4,
(DR, UL): 4,
(L, R): 4,
# UNDEFINED DIST PAIRS
(B, UNKNOWN): np.nan,
(BL, UNKNOWN): np.nan,
(BR, UNKNOWN): np.nan,
(D, UNKNOWN): np.nan,
(DB, UNKNOWN): np.nan,
(DBL, UNKNOWN): np.nan,
(DBR, UNKNOWN): np.nan,
(DF, UNKNOWN): np.nan,
(DFL, UNKNOWN): np.nan,
(DFR, UNKNOWN): np.nan,
(DL, UNKNOWN): np.nan,
(DR, UNKNOWN): np.nan,
(F, UNKNOWN): np.nan,
(FL, UNKNOWN): np.nan,
(FR, UNKNOWN): np.nan,
(L, UNKNOWN): np.nan,
(R, UNKNOWN): np.nan,
(U, UNKNOWN): np.nan,
(UB, UNKNOWN): np.nan,
(UBL, UNKNOWN): np.nan,
(UBR, UNKNOWN): np.nan,
(UF, UNKNOWN): np.nan,
(UFL, UNKNOWN): np.nan,
(UFR, UNKNOWN): np.nan,
(UL, UNKNOWN): np.nan,
(UNKNOWN, B): np.nan,
(UNKNOWN, BL): np.nan,
(UNKNOWN, BR): np.nan,
(UNKNOWN, D): np.nan,
(UNKNOWN, DB): np.nan,
(UNKNOWN, DBL): np.nan,
(UNKNOWN, DBR): np.nan,
(UNKNOWN, DF): np.nan,
(UNKNOWN, DFL): np.nan,
(UNKNOWN, DFR): np.nan,
(UNKNOWN, DL): np.nan,
(UNKNOWN, DR): np.nan,
(UNKNOWN, F): np.nan,
(UNKNOWN, FL): np.nan,
(UNKNOWN, FR): np.nan,
(UNKNOWN, L): np.nan,
(UNKNOWN, R): np.nan,
(UNKNOWN, U): np.nan,
(UNKNOWN, UB): np.nan,
(UNKNOWN, UBL): np.nan,
(UNKNOWN, UBR): np.nan,
(UNKNOWN, UF): np.nan,
(UNKNOWN, UFL): np.nan,
(UNKNOWN, UFR): np.nan,
(UNKNOWN, UL): np.nan,
(UNKNOWN, UR): np.nan,
(UR, UNKNOWN): np.nan,
(UNKNOWN, UNKNOWN): np.nan,
}
# make distance symmetric
for (f1, f2), d in list(VIEW_INT_DIST.items()):
VIEW_INT_DIST[(f2, f1)] = d
# Make string based version
VIEW_CODE_DIST = {
(INT_TO_CODE[f1], INT_TO_CODE[f2]): d for (f1, f2), d in VIEW_INT_DIST.items()
}
[docs]def RhombicuboctahedronDistanceDemo():
import utool as ut
def rhombicuboctahedro_faces():
"""yields names of all 26 rhombicuboctahedron faces"""
face_axes = [['up', 'down'], ['front', 'back'], ['left', 'right']]
ordering = {f: p for p, fs in enumerate(face_axes) for f in fs}
for i in range(1, len(face_axes) + 1):
for axes in list(ut.combinations(face_axes, i)):
for combo in ut.product(*axes):
sortx = ut.argsort(ut.take(ordering, combo))
face = tuple(ut.take(combo, sortx))
yield face
# Each face is a node.
import networkx as nx
G = nx.Graph()
faces = list(rhombicuboctahedro_faces())
G.add_nodes_from(faces)
# A fase is connected if they share an edge or a vertex
# TODO: is there a more general definition?
face_axes = [['up', 'down'], ['front', 'back'], ['left', 'right']]
ordering = {f: p for p, fs in enumerate(face_axes) for f in fs}
# In this case faces might share an edge or vertex if their names intersect
edges = []
for face1, face2 in ut.combinations(faces, 2):
set1 = set(face1)
set2 = set(face2)
if len(set1.intersection(set2)) > 0:
diff1 = set1.difference(set2)
diff2 = set2.difference(set1)
sortx1 = ut.argsort(ut.take(ordering, diff1))
sortx2 = ut.argsort(ut.take(ordering, diff2))
# If they share a name that is on opposite poles, then they cannot
# share an edge or vertex.
if not list(set(sortx1).intersection(set(sortx2))):
edges.append((face1, face2))
# print('-----')
# print('Edge: {} {}'.format(face1, face2))
# print('diff1 = {!r}'.format(diff1))
# print('diff2 = {!r}'.format(diff2))
G.add_edges_from(edges)
# Build distance lookup table
lookup = {}
for face1, face2 in ut.combinations(faces, 2):
# key = tuple(sorted([''.join(face1), ''.join(face2)]))
key = tuple(sorted([face1, face2]))
dist = nx.shortest_path_length(G, face1, face2)
lookup[key] = dist
def convert(face):
if face is None:
return 'UNKNOWN'
else:
return ''.join([p[0].upper() for p in face])
dist_lookup = {}
dist_lookup = {(convert(k1), convert(k2)): d for (k1, k2), d in lookup.items()}
for face in faces:
dist_lookup[(convert(face), convert(face))] = 0
dist_lookup[(convert(face), convert(None))] = None
dist_lookup[(convert(None), convert(face))] = None
dist_lookup[(convert(None), convert(None))] = None
# z = {'({}, {})'.format(k1, k2): d for (k1, k2), d in dist_lookup.items()}
# for i in range(0, 5):
# print(ub.repr2({k: v for k, v in z.items() if v == i}, si=True))
# i = None
# print(ub.repr2({k: v for k, v in z.items() if v == i}, si=True))
# z = ut.sort_dict(z, 'vals')
# print(ub.repr2(z, nl=2, si=True))
# if False:
# from wbia import constants as const
# VIEW = const.VIEW
# viewint_dist_lookup = {
# (VIEW.CODE_TO_INT[f1], VIEW.CODE_TO_INT[f2]): d
# (f1, f2) for (f1, f2), d in viewcode_dist_lookup.items()
# }
# for k, v in viewcode_dist_lookup.items():
# if 'up' not in k[0] and 'down' not in k[0]:
# if 'up' not in k[1] and 'down' not in k[1]:
# print(k, v)
def visualize_connection_graph():
# node_to_group = {f: str(len(f)) for f in faces}
node_to_group = {}
for f in faces:
if 'up' in f:
node_to_group[f] = '0.' + str(len(f))
elif 'down' in f:
node_to_group[f] = '1.' + str(len(f))
else:
node_to_group[f] = '2.' + str(len(f))
nx.set_node_attributes(G, name='groupid', values=node_to_group)
node_to_label = {f: ''.join(ut.take_column(f, 0)).upper() for f in faces}
nx.set_node_attributes(G, name='label', values=node_to_label)
import wbia.plottool as pt
pt.qt4ensure()
pt.show_nx(G, prog='neato', groupby='groupid')
visualize_connection_graph()