def getGraph(self) -> List[Tuple[int, int]]: """Return edges data for NetworkX graph class. + VLinks will become graph nodes. """ vpoints = self.EntitiesPoint.dataTuple() vlinks = self.EntitiesLink.dataTuple() graph = Graph([]) # links name for RP joint. k = len(vlinks) used_point = set() # Link names will change to index number. for i, vlink in enumerate(vlinks): for p in vlink.points: if p in used_point: continue for m, vlink_ in enumerate(vlinks): if not ((i != m) and (p in vlink_.points)): continue if vpoints[p].type != VPoint.RP: graph.add_edge(i, m) continue graph.add_edge(i, k) graph.add_edge(k, m) k += 1 used_point.add(p) return [edge for n, edge in edges_view(graph)]
def four_bar_loops(G): result = set([]) vertexes = {v: k for k, v in edges_view(G)} for node in G.nodes: if node in result: continue nb1s = G.neighbors(node) #node not in nb1s for nb1 in nb1s: if nb1 in result: continue nb2s = G.neighbors(nb1) #node can not in nb2s for nb2 in nb2s: if (nb2 == node) or (nb2 in result): continue nb3s = G.neighbors(nb2) #node can not in nb3s for nb3 in nb3s: if (nb3 in (node, nb1)) or (nb3 in result): continue if node in G.neighbors(nb3): result.update([node, nb1, nb2, nb3]) yield tuple(vertexes[tuple(sorted(e))] for e in [(node, nb1), (nb1, nb2), (nb2, nb3), (node, nb3)])
def four_bar_loops(G: Graph) -> Tuple[int, int, int, int]: """A generator to find out the four bar loops.""" result = set([]) vertexes = {v: k for k, v in edges_view(G)} def loop_set(node: int, nb1: int, nb2: int, nb3: int) -> Tuple[int, int, int, int]: """Return a loop set.""" tmp_list = [] for e in [(node, nb1), (nb1, nb2), (nb2, nb3), (node, nb3)]: tmp_list.append(vertexes[tuple(sorted(e))]) return tuple(tmp_list) for node in G.nodes: if node in result: continue nb1s = G.neighbors(node) #node not in nb1s for nb1 in nb1s: if nb1 in result: continue nb2s = G.neighbors(nb1) #node can not in nb2s for nb2 in nb2s: if (nb2 == node) or (nb2 in result): continue nb3s = G.neighbors(nb2) #node can not in nb3s for nb3 in nb3s: if (nb3 in (node, nb1)) or (nb3 in result): continue if node in G.neighbors(nb3): loop = [node, nb1, nb2, nb3] result.update(loop) yield loop_set(*loop)
def getGraph(self) -> List[Tuple[int, int]]: """Return edges data for NetworkX graph class. + VLinks will become graph nodes. """ joint_data = self.EntitiesPoint.dataTuple() link_data = self.EntitiesLink.dataTuple() G = Graph() # links name for RP joint. k = len(link_data) used_point = set() for i, vlink in enumerate(link_data): for p in vlink.points: if p in used_point: continue for m, vlink_ in enumerate(link_data): if not ((i != m) and (p in vlink_.points)): continue if joint_data[p].type != 2: G.add_edge(i, m) continue G.add_edge(i, k) G.add_edge(k, m) k += 1 used_point.add(p) return [edge for n, edge in edges_view(G)]
def setGraph(self, G, pos): self.clear() self.PreviewWindow.setGraph(G, pos) for link in G.nodes: self.grounded_list.addItem("({})".format(", ".join( 'P{}'.format(n) for n, edge in edges_view(G) if link in edge))) #Point name as (P1, P2, P3, ...). for node in pos: self.joint_name.addItem('P{}'.format(node))
def find_friends(node: int): """Find all the nodes that are same link with input node.""" ev = dict(edges_view(self.PreviewWindow.G)) link = set(ev[node]) tmp_list = [] for node_, link_ in ev.items(): if node_ == node: continue if set(link_) & link: tmp_list.append(f'P{node_}') return tmp_list
def on_load_button_clicked(self): """Show up the dialog to load structure data.""" dlg = CollectionsDialog(self) dlg.show() if not dlg.exec_(): return self.profile_name = dlg.name_loaded params = dlg.mechanismParams mapping = params['name_dict'] #Add customize joints. G = Graph(params['Graph']) self.setGraph(G, params['pos']) self.PreviewWindow.cus = params['cus'] self.PreviewWindow.same = params['same'] #Grounded setting. Driver = [mapping[e] for e in params['Driver']] Follower = [mapping[e] for e in params['Follower']] for row, link in enumerate(G.nodes): points = set('P{}'.format(n) for n, edge in edges_view(G) if link in edge) if set(Driver + Follower) <= points: self.grounded_list.setCurrentRow(row) break #Driver, Follower, Target for row in reversed(range(self.Follower_list.count())): if self.Follower_list.item(row).text() in Driver: self.Follower_list.setCurrentRow(row) self.Driver_add.click() self.Target_list.addItems([mapping[e] for e in params['Target']]) self.setWarning(self.Target_label, not self.Target_list.count() > 0) #Constraints self.constraint_list.addItems( [", ".join(mapping[e] for e in c) for c in params['constraint']]) #Expression for expr in params['Expression'].split(';'): params = get_from_parenthesis(expr, '[', ']').split(',') target = get_from_parenthesis(expr, '(', ')') params.append(target) for p in params: try: #Try to avoid replace function name. expr = mapping[p].join(expr.rsplit(p, 1)) except KeyError: continue item = QListWidgetItem() self.Expression_list.addItem(item) item.setText(expr) self.PreviewWindow.setStatus(mapping[target], True) self.setWarning(self.Expression_list_label, not self.PreviewWindow.isAllLock())
def __load_data_base(self): """Show up the dialog to load structure data.""" dlg = CollectionsDialog(self.collections, self.getCollection, self) dlg.show() if not dlg.exec_(): return self.profile_name = dlg.name() params = dlg.params() # Add customize joints. graph = Graph(params['Graph']) self.setGraph(graph, params['pos']) self.PreviewWindow.cus = params['cus'] self.PreviewWindow.same = params['same'] # Grounded setting. drivers = set(params['Driver']) followers = set(params['Follower']) for row, link in enumerate(graph.nodes): points = {f'P{n}' for n, edge in edges_view(graph) if link in edge} if (drivers | followers) <= points: self.__set_ground(row) break # Driver, Follower, Target for expr in params['Expression'].split(';'): if str_before(expr, '[') != 'PLAP': continue base = str_between(expr, '[', ']').split(',')[0] self.__find_follower_to_remove(base) rotator = str_between(expr, '(', ')') self.driver_list.addItem(f"({base}, {rotator})") _set_warning(self.driver_label, not self.driver_list.count()) self.target_list.addItems(list(params['Target'])) _set_warning(self.target_label, not self.target_list.count() > 0) # Constraints self.constraint_list.addItems( [", ".join(c) for c in params['constraints']]) # Expression if params['Expression']: for expr in params['Expression'].split(';'): func = str_before(expr, '[') target = str_between(expr, '(', ')') params = str_between(expr, '[', ']').split(',') params.insert(0, func) params.append(target) self.__add_solution(*params) self.PreviewWindow.setStatus(target, True) _set_warning(self.expression_list_label, not self.PreviewWindow.isAllLock())
def on_load_button_clicked(self): """Show up the dialog to load structure data.""" dlg = CollectionsDialog(self) dlg.show() if not dlg.exec_(): return self.profile_name = dlg.name_loaded params = dlg.mech_params #Add customize joints. G = Graph(params['Graph']) self.setGraph(G, params['pos']) self.PreviewWindow.cus = params['cus'] self.PreviewWindow.same = params['same'] #Grounded setting. drivers = set(params['Driver']) followers = set(params['Follower']) for row, link in enumerate(G.nodes): points = set('P{}'.format(n) for n, edge in edges_view(G) if link in edge) if (drivers | followers) <= points: self.grounded_list.setCurrentRow(row) break #Driver, Follower, Target for expr in params['Expression'].split(';'): if strbefore(expr, '[') != 'PLAP': continue base = strbetween(expr, '[', ']').split(',')[0] self.__find_follower_to_remove(base) rotator = strbetween(expr, '(', ')') self.driver_list.addItem("({}, {})".format(base, rotator)) self.__setWarning(self.driver_label, not self.driver_list.count()) self.target_list.addItems(list(params['Target'])) self.__setWarning(self.target_label, not self.target_list.count() > 0) #Constraints self.constraint_list.addItems( [", ".join(c) for c in params['constraint']]) #Expression for expr in params['Expression'].split(';'): func = strbefore(expr, '[') target = strbetween(expr, '(', ')') params = strbetween(expr, '[', ']').split(',') params.insert(0, func) params.append(target) self.__addSolution(*params) self.PreviewWindow.setStatus(target, True) self.__setWarning(self.expression_list_label, not self.PreviewWindow.isAllLock())
def addPointsByGraph(self, G: Graph, pos: Dict[int, Tuple[float, float]], ground_link: int): """Add points by networkx graph and position dict.""" base_count = self.EntitiesPoint.rowCount() self.CommandStack.beginMacro( "Merge mechanism kit from {Number and Type Synthesis}") for i in range(len(pos)): self.addPoint(*pos[i]) for link in G.nodes: self.addLink( _getLinkSerialNumber(self), 'Blue', [base_count + n for n, edge in edges_view(G) if (link in edge)]) if link == ground_link: ground = self.EntitiesLink.rowCount() - 1 self.CommandStack.endMacro() if ground_link is not None: self.constrainLink(ground)
def setGraph(self, G: Graph, pos: Dict[int, Tuple[float, float]]): """Set the graph to preview canvas.""" self.clear() self.PreviewWindow.setGraph(G, pos) ev = dict(edges_view(G)) joints_count = set() for l1, l2 in ev.values(): joints_count.update({l1, l2}) links = [[] for i in range(len(joints_count))] for joint, link in ev.items(): for node in link: links[node].append(joint) for link in links: self.grounded_list.addItem("({})".format(", ".join( 'P{}'.format(node) for node in link))) #Point name as (P1, P2, P3, ...). for node in pos: self.joint_name.addItem('P{}'.format(node))
def setGraph(self, graph: Graph, pos: Dict[int, Tuple[float, float]]): """Set the graph to preview canvas.""" self.__clear_panel() self.PreviewWindow.setGraph(graph, pos) ev = dict(edges_view(graph)) joints_count = set() for l1, l2 in ev.values(): joints_count.update({l1, l2}) links = [] for i in range(len(joints_count)): links.append([]) for joint, link in ev.items(): for node in link: links[node].append(joint) for link in links: points_text = ", ".join(f'P{node}' for node in link) self.grounded_list.addItem(f"({points_text})") # Point name as (P1, P2, P3, ...). for node in pos: self.joint_name.addItem(f'P{node}')
def addPointsByGraph(self, graph: Graph, pos: Dict[int, Tuple[float, float]], ground_link: Optional[int]): """Add points by NetworkX graph and position dict.""" base_count = self.EntitiesPoint.rowCount() self.CommandStack.beginMacro( "Merge mechanism kit from {Number and Type Synthesis}") for i in range(len(pos)): x, y = pos[i] self.addPoint(x, y) ground: Optional[int] = None for link in graph.nodes: self.addLink(self.__get_link_serial_number(), 'Blue', [ base_count + n for n, edge in edges_view(graph) if link in edge ]) if link == ground_link: ground = self.EntitiesLink.rowCount() - 1 self.CommandStack.endMacro() if ground_link is not None: self.constrainLink(ground)
def _four_bar_loops(graph: Graph) -> Iterator[Tuple[int, int, int, int]]: """A generator to find out the four bar loops.""" result = set() vertexes = {v: k for k, v in edges_view(graph)} def loop_set(n: int, n1: int, n2: int, n3: int) -> Tuple[int, int, int, int]: """Return a loop set.""" return ( vertexes[tuple(sorted((n, n1)))], vertexes[tuple(sorted((n1, n2)))], vertexes[tuple(sorted((n2, n3)))], vertexes[tuple(sorted((n, n3)))], ) for node in graph.nodes: if node in result: continue nb1s = graph.neighbors(node) # node not in nb1s for nb1 in nb1s: if nb1 in result: continue nb2s = graph.neighbors(nb1) # node can not in nb2s for nb2 in nb2s: if (nb2 == node) or (nb2 in result): continue nb3s = graph.neighbors(nb2) # node can not in nb3s for nb3 in nb3s: if (nb3 in (node, nb1)) or (nb3 in result): continue if node in graph.neighbors(nb3): loop = [node, nb1, nb2, nb3] result.update(loop) yield loop_set(*loop)
def friends(self, node1: int, reliable: bool = False) -> int: """Return a generator yield the nodes that has solution on the same link. """ #All edges of all nodes. edges = dict(edges_view(self.G)) for n, l in self.cus.items(): edges[int(n.replace('P', ''))] = (l, ) #Reverse dict of 'self.same'. same_r = {v: k for k, v in self.same.items()} #for all link of node1. links1 = set(edges[node1]) if node1 in same_r: links1.update(edges[same_r[node1]]) #for all link. for node2 in edges: if (node1 == node2) or (node2 in self.same): continue links2 = set(edges[node2]) if node2 in same_r: links2.update(edges[same_r[node2]]) #Reference by intersection and status. if (links1 & links2) and (not self.getStatus(node2) != reliable): yield node2