def from_profile(self, params: Dict[str, Any]) -> None: """Simple load by dict object.""" # Customize points and multiple joints g = Graph(params['graph']) expression: str = params['expression'] pos_list = parse_pos(expression) cus: Dict[int, int] = params['cus'] same: Dict[int, int] = params['same'] self.cus = cus self.same = same for node, ref in sorted(self.same.items()): pos_list.insert(node, pos_list[ref]) self.set_graph(g, {i: (x, y) for i, (x, y) in enumerate(pos_list)}) # Grounded setting for row in self.grounded_detect(set(params['placement']), g, self.same): self.set_grounded(row) # Driver setting input_list: List[Tuple[Tuple[int, int], Tuple[float, float]]] = params['input'] self.driver.clear() self.driver.update(b for (b, _), _ in input_list) # Target setting target: Dict[int, Sequence[_Coord]] = params['target'] self.target.clear() self.target.update(target) self.update()
def __from_profile(self) -> None: """Show up the dialog to load structure data.""" dlg = CollectionsDialog( self.collections, self.get_configure, self.project_no_save, self.prefer.tick_mark_option, self.configure_canvas.monochrome, self ) dlg.show() if not dlg.exec_(): dlg.deleteLater() return # Add customize joints params = dlg.params graph = Graph(params['graph']) expression: str = params['expression'] pos_list = parse_pos(expression) cus: Dict[int, int] = params['cus'] same: Dict[int, int] = params['same'] for node, ref in sorted(same.items()): pos_list.insert(node, pos_list[ref]) if not self.set_graph(graph, {i: (x, y) for i, (x, y) in enumerate(pos_list)}): dlg.deleteLater() return self.profile_name.setText(dlg.name) dlg.deleteLater() del dlg self.configure_canvas.cus = cus self.configure_canvas.same = same # Grounded setting for row in PreviewCanvas.grounded_detect(set(params['placement']), graph, same): self.__set_grounded(row) # Driver, Target input_list: List[Tuple[Tuple[int, int], Tuple[float, float]]] = params['input'] self.driver_list.addItems(f"(P{b}, P{d})" for (b, d), _ in input_list) self.configure_canvas.set_driver([d for d, _ in input_list]) _set_warning(self.driver_label, self.driver_list.count() == 0) target_list: Dict[int, Sequence[_Coord]] = params['target'] self.configure_canvas.set_target(sorted(target_list)) self.target_list.addItems(f"P{n}" for n in target_list) _set_warning(self.target_label, self.target_list.count() == 0) # Expression self.expr_show.setText(params['expression'])
def __set_profile(self, profile_name: str, params: Dict[str, Any]) -> None: """Set profile to sub-widgets.""" self.__clear_settings() self.mech = deepcopy(params) expression: str = self.mech['expression'] self.expression_string.setText(expression) target: Dict[int, List[_Coord]] = self.mech['target'] for p in sorted(target): self.target_points.addItem(f"P{p}") if target[p]: self.path[p] = target[p].copy() else: self.path[p] = [] if self.has_target(): self.target_points.setCurrentRow(0) self.target_label.setVisible(self.has_target()) inputs: List[Tuple[_Pair, List[float]]] = self.mech.get('input', []) self.mech['input'] = inputs placement: Dict[int, Optional[_Range]] = self.mech.get('placement', {}) self.mech['placement'] = placement # Table settings self.parameter_list.setRowCount(0) self.parameter_list.setRowCount(len(inputs) + len(placement) + 1) row = 0 def spinbox( v: float = 0., *, minimum: float = 0., maximum: float = 9999., prefix: bool = False ) -> QDoubleSpinBox: double_spinbox = QDoubleSpinBox() double_spinbox.setMinimum(minimum) double_spinbox.setMaximum(maximum) double_spinbox.setValue(v) if prefix: double_spinbox.setPrefix("±") return double_spinbox def set_angle(index1: int, index2: int) -> Callable[[float], None]: """Return a slot function use to set angle value.""" @Slot(float) def func(value: float) -> None: inputs[index1][1][index2] = value return func # Angles for i, ((b, d), se) in enumerate(inputs): self.parameter_list.setItem(row, 0, QTableWidgetItem(f"P{b}->P{d}")) self.parameter_list.setItem(row, 1, QTableWidgetItem('input')) s1 = spinbox(se[0], maximum=360.) s2 = spinbox(se[1], maximum=360.) self.parameter_list.setCellWidget(row, 2, s1) self.parameter_list.setCellWidget(row, 3, s2) s1.valueChanged.connect(set_angle(i, 0)) s2.valueChanged.connect(set_angle(i, 1)) row += 1 # Grounded joints self.preview_canvas.from_profile(self.mech) pos_list = parse_pos(expression) for node, ref in sorted(self.preview_canvas.same.items()): pos_list.insert(node, pos_list[ref]) for p in sorted(placement): coord = placement[p] self.parameter_list.setItem(row, 0, QTableWidgetItem(f"P{p}")) self.parameter_list.setItem(row, 1, QTableWidgetItem('placement')) x, y = self.preview_canvas.pos[p] for i, s in enumerate([ spinbox(coord[0] if coord else x, minimum=-9999.), spinbox(coord[1] if coord else y, minimum=-9999.), spinbox(coord[2] if coord else 5., prefix=True), ]): s.valueChanged.connect(self.update_range) self.parameter_list.setCellWidget(row, i + 2, s) row += 1 # Default value of upper and lower self.mech['upper'] = self.mech.get('upper', 100) self.mech['lower'] = self.mech.get('lower', 0) def set_link(opt: str) -> Callable[[float], None]: """Set link length.""" @Slot(float) def func(value: float) -> None: self.mech[opt] = value return func self.parameter_list.setItem(row, 0, QTableWidgetItem("L")) self.parameter_list.setItem(row, 1, QTableWidgetItem('link')) for i, (s, tag) in enumerate([(spinbox(), 'upper'), (spinbox(), 'lower')]): s.setValue(self.mech[tag]) s.valueChanged.connect(set_link(tag)) self.parameter_list.setCellWidget(row, i + 2, s) # Update previews self.update_range() self.profile_name.setText(profile_name) # Default value of algorithm option if 'settings' in self.mech: self.alg_options.update(self.mech['settings']) else: self.__set_algorithm_default() self.__able_to_generate()
def __set_profile(self, profile_name: str, params: Dict[str, Any]) -> None: """Set profile to sub-widgets.""" self.__clear_settings() self.mech_params = deepcopy(params) expression: str = self.mech_params['Expression'] self.expression_string.setText(expression) target: Dict[int, List[_Coord]] = self.mech_params['Target'] for name in sorted(target): self.target_points.addItem(f"P{name}") path = target[name] if path: self.path[name] = path.copy() else: self.path[name] = [] if self.has_target(): self.target_points.setCurrentRow(0) self.target_label.setVisible(self.has_target()) # Parameter of link length and input angle. link_list = set() for vlink in parse_vlinks(expression): if len(vlink.points) < 2 or vlink.name == "ground": continue a = vlink.points[0] b = vlink.points[1] link_list.add(f"P{a}<->P{b}") for c in vlink.points[2:]: for d in (a, b): link_list.add(f"P{c}<->P{d}") link_count = len(link_list) angle_list = set() input_list: List[Tuple[int, int]] = self.mech_params['input'] for b, d in input_list: angle_list.add(f"P{b}->P{d}") angle_count = len(angle_list) self.parameter_list.setRowCount(0) placement: Dict[int, Tuple[float, float, float]] = self.mech_params['Placement'] self.parameter_list.setRowCount( len(placement) + link_count + angle_count) def spinbox(v: float, *, minimum: float = 0., maximum: float = 9999., prefix: bool = False) -> QDoubleSpinBox: double_spinbox = QDoubleSpinBox() double_spinbox.setMinimum(minimum) double_spinbox.setMaximum(maximum) double_spinbox.setSingleStep(10.0) double_spinbox.setValue(v) if prefix: double_spinbox.setPrefix("±") return double_spinbox # Position self.preview_canvas.from_profile(self.mech_params) pos_list = parse_pos(expression) for node, ref in sorted(self.preview_canvas.same.items()): pos_list.insert(node, pos_list[ref]) row = 0 for name in sorted(placement): coord = placement[name] self.parameter_list.setItem(row, 0, QTableWidgetItem(f"P{name}")) self.parameter_list.setItem(row, 1, QTableWidgetItem('Placement')) x, y = self.preview_canvas.pos[name] for i, s in enumerate([ spinbox(coord[0] if coord else x, minimum=-9999.), spinbox(coord[1] if coord else y, minimum=-9999.), spinbox(coord[2] if coord else 25., prefix=True), ]): s.valueChanged.connect(self.update_range) self.parameter_list.setCellWidget(row, i + 2, s) row += 1 # Default value of upper and lower for name in ('upper', 'lower'): if name not in self.mech_params: self.mech_params[name] = [0.] * (link_count + angle_count) upper_list: List[float] = self.mech_params['upper'] lower_list: List[float] = self.mech_params['lower'] def set_by_center( index: int, get_range: Callable[[], float]) -> Callable[[float], None]: """Return a slot function use to set limit value by center.""" @Slot(float) def func(value: float) -> None: range_value = get_range() upper_list[index] = value + range_value lower_list[index] = value - range_value return func def set_by_range( index: int, get_value: Callable[[], float]) -> Callable[[float], None]: """Return a slot function use to set limit value by range.""" @Slot(float) def func(value: float) -> None: center = get_value() upper_list[index] = center + value lower_list[index] = center - value return func for i, name in enumerate(sorted(link_list) + sorted(angle_list)): name_item = QTableWidgetItem(name) name_item.setToolTip(name) self.parameter_list.setItem(row, 0, name_item) upper = upper_list[i] lower = lower_list[i] if name in link_list: type_name = "Link" n1, n2 = (int(n.replace('P', '')) for n in name.split('<->')) link_length = self.preview_canvas.distance(n1, n2) if upper == 0.: upper = link_length + 50 if lower <= 0.: lower = link_length - 50 lower = 0. if lower < 0 else lower else: type_name = "Input" if upper == 0.: upper = 360. self.parameter_list.setItem(row, 1, QTableWidgetItem(type_name)) # Set values upper_list[i] = upper lower_list[i] = lower # Spin box error_range = (upper - lower) / 2 default_value = error_range + lower if name in link_list: s1 = spinbox(default_value) else: s1 = spinbox(default_value, maximum=360.) self.parameter_list.setCellWidget(row, 2, s1) s2 = spinbox(error_range, prefix=True) self.parameter_list.setCellWidget(row, 4, s2) # Signals s1.valueChanged.connect(set_by_center(i, s2.value)) s2.valueChanged.connect(set_by_range(i, s1.value)) row += 1 self.update_range() self.profile_name.setText(profile_name) # Default value of algorithm option. if 'settings' in self.mech_params: self.alg_options.update(self.mech_params['settings']) else: self.__set_algorithm_default() self.__able_to_generate()
def __set_profile(self, profile_name: str, params: Dict[str, Any]) -> None: """Set profile to sub-widgets.""" self.__clear_settings() self.mech = deepcopy(params) expression: str = self.mech['expression'] self.expression_string.setText(expression) target: Dict[int, List[_Coord]] = self.mech['target'] for p in sorted(target): self.target_points.addItem(f"P{p}") if target[p]: self.path[p] = target[p].copy() else: self.path[p] = [] if self.has_target(): self.target_points.setCurrentRow(0) self.target_label.setVisible(self.has_target()) # Parameter of link length and input angle. link_list = [] for vlink in parse_vlinks(expression): if len(vlink.points) < 2 or vlink.name == VLink.FRAME: continue a = vlink.points[0] b = vlink.points[1] link_list.append((a, b)) for c in vlink.points[2:]: for d in (a, b): link_list.append((c, d)) link_count = len(link_list) inputs: List[Tuple[Tuple[int, int], List[float]]] = self.mech['input'] self.parameter_list.setRowCount(0) placement: Dict[int, Optional[Tuple[float, float, float]]] = self.mech['placement'] # Table settings self.parameter_list.setRowCount( len(inputs) + len(placement) + link_count) row = 0 def spinbox(v: float, *, minimum: float = 0., maximum: float = 9999., prefix: bool = False) -> QDoubleSpinBox: double_spinbox = QDoubleSpinBox() double_spinbox.setMinimum(minimum) double_spinbox.setMaximum(maximum) double_spinbox.setValue(v) if prefix: double_spinbox.setPrefix("±") return double_spinbox def set_angle(index1: int, index2: int) -> Callable[[float], None]: """Return a slot function use to set angle value.""" @Slot(float) def func(value: float) -> None: inputs[index1][1][index2] = value return func # Angles for i, ((b, d), se) in enumerate(inputs): self.parameter_list.setItem(row, 0, QTableWidgetItem(f"P{b}->P{d}")) self.parameter_list.setItem(row, 1, QTableWidgetItem('input')) s1 = spinbox(se[0], maximum=360.) s2 = spinbox(se[1], maximum=360.) self.parameter_list.setCellWidget(row, 2, s1) self.parameter_list.setCellWidget(row, 3, s2) s1.valueChanged.connect(set_angle(i, 0)) s2.valueChanged.connect(set_angle(i, 1)) row += 1 # Grounded joints self.preview_canvas.from_profile(self.mech) pos_list = parse_pos(expression) for node, ref in sorted(self.preview_canvas.same.items()): pos_list.insert(node, pos_list[ref]) for p in sorted(placement): coord = placement[p] self.parameter_list.setItem(row, 0, QTableWidgetItem(f"P{p}")) self.parameter_list.setItem(row, 1, QTableWidgetItem('placement')) x, y = self.preview_canvas.pos[p] for i, s in enumerate([ spinbox(coord[0] if coord else x, minimum=-9999.), spinbox(coord[1] if coord else y, minimum=-9999.), spinbox(coord[2] if coord else 25., prefix=True), ]): s.valueChanged.connect(self.update_range) self.parameter_list.setCellWidget(row, i + 2, s) row += 1 # Default value of upper and lower upper_list: List[float] = self.mech.get('upper', [0.] * link_count) lower_list: List[float] = self.mech.get('lower', [0.] * link_count) self.mech['upper'] = upper_list self.mech['lower'] = lower_list def set_by_center( index: int, get_range: Callable[[], float]) -> Callable[[float], None]: """Return a slot function use to set limit value by center.""" @Slot(float) def func(value: float) -> None: range_value = get_range() upper_list[index] = value + range_value lower_list[index] = value - range_value return func def set_by_range( index: int, get_value: Callable[[], float]) -> Callable[[float], None]: """Return a slot function use to set limit value by range.""" @Slot(float) def func(value: float) -> None: center = get_value() upper_list[index] = center + value lower_list[index] = center - value return func # Links for i, (a, b) in enumerate(sorted(link_list)): self.parameter_list.setItem(row, 0, QTableWidgetItem(f"P{a}<->P{b}")) link_length = self.preview_canvas.distance(a, b) self.parameter_list.setItem(row, 1, QTableWidgetItem('link')) # Set values if upper_list[i] == 0.: upper_list[i] = link_length + 50 if lower_list[i] <= 0.: lower_list[i] = link_length - 50 lower_list[i] = 0. if lower_list[i] < 0 else lower_list[i] # Spinbox error_range = (upper_list[i] - lower_list[i]) / 2 s1 = spinbox(error_range + lower_list[i]) s2 = spinbox(error_range, prefix=True) self.parameter_list.setCellWidget(row, 2, s1) self.parameter_list.setCellWidget(row, 4, s2) s1.valueChanged.connect(set_by_center(i, s2.value)) s2.valueChanged.connect(set_by_range(i, s1.value)) row += 1 self.update_range() self.profile_name.setText(profile_name) # Default value of algorithm option. if 'settings' in self.mech: self.alg_options.update(self.mech['settings']) else: self.__set_algorithm_default() self.__able_to_generate()