예제 #1
0
 def point_alignment(self) -> None:
     """Alignment function."""
     selected_rows = self.entities_point.selected_rows()
     if not selected_rows:
         QMessageBox.warning(self, "Points alignment",
                             "No selected points with this operation.")
         return
     if self.alignment_mode == 0:
         axis = "x"
     elif self.alignment_mode == 1:
         axis = "y"
     else:
         raise ValueError("no such alignment option")
     value, ok = QInputDialog.getDouble(
         self, f"Set {axis} axis",
         f"Align the selected points into {axis} axis:", 0, -9999, 9999, 4)
     if not ok:
         return
     self.command_stack.beginMacro(f"Align points with {axis}")
     for row in selected_rows:
         args = self.entities_point.row_data(row)
         if self.alignment_mode == 0:
             args.x = value
         elif self.alignment_mode == 1:
             args.y = value
         else:
             raise ValueError("no such alignment option")
         self.command_stack.push(
             EditPointTable(row, self.vpoint_list, self.vlink_list,
                            self.entities_point, self.entities_link, args))
     self.command_stack.endMacro()
예제 #2
0
 def __set_link_length(self) -> None:
     """Set link length."""
     dlg = _LinkLengthDialog(self)
     dlg.show()
     if not dlg.exec_():
         return
     data = {(dlg.get_leader(), dlg.get_follower()): dlg.get_length()}
     dlg.deleteLater()
     system = SolverSystem(
         self.vpoint_list,
         {(b, d): a
          for b, d, a in self.inputs_widget.input_pairs()})
     system.set_data(data)
     try:
         result = system.solve()
     except ValueError:
         QMessageBox.warning(self, "Solved error",
                             "The condition is not valid.")
         return
     self.command_stack.beginMacro(f"Set link length:{set(data)}")
     for row, c in enumerate(result):
         args = self.entities_point.row_data(row)
         if isinstance(c[0], float):
             args.x, args.y = c
         else:
             (args.x, args.y), _ = c
         self.command_stack.push(
             EditPointTable(row, self.vpoint_list, self.vlink_list,
                            self.entities_point, self.entities_link, args))
     self.command_stack.endMacro()
예제 #3
0
    def __edit_point(self, row: Union[int, bool] = False) -> None:
        """Edit point function."""
        dlg = EditPointDialog(self.vpoint_list, self.vlink_list, row, self)
        dlg.show()
        if not dlg.exec_():
            dlg.deleteLater()
            return

        row_count = self.entities_point.rowCount()
        type_str = dlg.type_box.currentText().split()[0]
        if type_str != 'R':
            type_str += f":{dlg.angle_box.value() % 360}"
        args = PointArgs(
            ','.join(
                dlg.selected.item(link).text()
                for link in range(dlg.selected.count())), type_str,
            dlg.color_box.currentText(), dlg.x_box.value(), dlg.y_box.value())
        if row is False:
            self.command_stack.beginMacro(f"Add {{Point{row_count}}}")
            self.command_stack.push(
                AddTable(self.vpoint_list, self.entities_point))
            row = row_count
        else:
            row = dlg.name_box.currentIndex()
            self.command_stack.beginMacro(f"Edit {{Point{row}}}")

        dlg.deleteLater()

        self.command_stack.push(
            EditPointTable(row, self.vpoint_list, self.vlink_list,
                           self.entities_point, self.entities_link, args))
        self.command_stack.endMacro()
예제 #4
0
 def delete_point(self, row: Optional[int] = None) -> None:
     """Push delete point command to stack."""
     if row is None:
         row = self.entities_point.currentRow()
     if row < 0:
         return
     args = self.entities_point.row_data(row)
     args.links = ''
     self.command_stack.beginMacro(f"Delete {{Point{row}}}")
     for i in reversed([
             i
             for i, (b, d, _) in enumerate(self.inputs_widget.input_pairs())
             if row in {b, d}
     ]):
         self.inputs_widget.remove_var(i)
     self.command_stack.push(
         EditPointTable(row, self.vpoint_list, self.vlink_list,
                        self.entities_point, self.entities_link, args))
     for i in range(self.entities_link.rowCount()):
         self.command_stack.push(
             FixSequenceNumber(self.vlink_list, self.entities_link, i, row))
     self.command_stack.push(
         DeleteTable(row,
                     self.vpoint_list,
                     self.entities_point,
                     is_rename=True))
     self.inputs_widget.variable_excluding(row)
     self.command_stack.endMacro()
     if self.prefer.auto_remove_link_option:
         self.delete_redundant_links()
예제 #5
0
 def lock_points(self) -> None:
     """Turn a group of points to fixed on ground or not."""
     to_fixed = self.action_p_lock.isChecked()
     selected_rows = self.entities_point.selected_rows()
     self.cmd_stack.beginMacro(
         f"{'Grounded' if to_fixed else 'Ungrounded'} "
         f"{sorted(selected_rows)}"
     )
     for row in selected_rows:
         new_links = list(self.vpoint_list[row].links)
         if to_fixed:
             if VLink.FRAME not in new_links:
                 new_links.append(VLink.FRAME)
         elif VLink.FRAME in new_links:
             new_links.remove(VLink.FRAME)
         args = self.entities_point.row_data(row)
         args.links = ','.join(s for s in new_links if s)
         self.cmd_stack.push(EditPointTable(
             row,
             self.vpoint_list,
             self.vlink_list,
             self.entities_point,
             self.entities_link,
             args
         ))
     self.cmd_stack.endMacro()
예제 #6
0
 def add_point(
     self,
     x: float,
     y: float,
     links: str = "",
     color: str = 'Green',
     type_num: Union[int, VJoint] = VJoint.R,
     angle: float = 0.
 ) -> int:
     """Add an ordinary point. Return the row count of new point."""
     row_count = self.entities_point.rowCount()
     self.cmd_stack.beginMacro(f"Add {{Point{row_count}}}")
     self.cmd_stack.push(AddTable(self.vpoint_list, self.entities_point))
     if type_num == VJoint.R:
         type_str = 'R'
     elif type_num == VJoint.P:
         type_str = f'P:{angle}'
     else:
         type_str = f'RP:{angle}'
     self.cmd_stack.push(EditPointTable(
         row_count,
         self.vpoint_list,
         self.vlink_list,
         self.entities_point,
         self.entities_link,
         PointArgs(links, type_str, color, x, y)
     ))
     self.cmd_stack.endMacro()
     return row_count
예제 #7
0
 def parse_expression(self, expr: str) -> None:
     """Parse expression."""
     try:
         args_list = parse_params(expr)
     except LarkError:
         QMessageBox.warning(
             self,
             "Loading failed",
             f"Your expression is in an incorrect format."
         )
     else:
         for args in args_list:
             links = args.links.split(',')
             link_names = {vlink.name for vlink in self.vlink_list}
             for link_name in links:
                 # If link name not exist
                 if link_name not in link_names:
                     self.add_link(link_name, 'Blue')
             row_count = self.entities_point.rowCount()
             self.command_stack.beginMacro(f"Add {{Point{row_count}}}")
             self.command_stack.push(AddTable(
                 self.vpoint_list,
                 self.entities_point
             ))
             self.command_stack.push(EditPointTable(
                 row_count,
                 self.vpoint_list,
                 self.vlink_list,
                 self.entities_point,
                 self.entities_link,
                 args
             ))
             self.command_stack.endMacro()
예제 #8
0
    def __to_multiple_joint(self, index: int, points: Sequence[int]) -> None:
        """Merge points into a multiple joint.

        @index: The index of main joint in the sequence.
        """
        row = points[index]
        self.command_stack.beginMacro(
            f"Merge {sorted(points)} as multiple joint {{Point{row}}}"
        )
        links = list(self.vpoint_list[row].links)
        args = self.entities_point.row_data(row)
        for point in sorted(points, reverse=True):
            for link in self.vpoint_list[point].links:
                if link not in links:
                    links.append(link)
            self.delete_point(point)
        args.links = ','.join(links)
        self.command_stack.push(AddTable(self.vpoint_list, self.entities_point))
        self.command_stack.push(EditPointTable(
            self.entities_point.rowCount() - 1,
            self.vpoint_list,
            self.vlink_list,
            self.entities_point,
            self.entities_link,
            args
        ))
        self.command_stack.endMacro()
예제 #9
0
 def clone_point(self) -> None:
     """Clone a point (with orange color)."""
     row = self.entities_point.currentRow()
     args = self.entities_point.row_data(row)
     args.color = 'Orange'
     row_count = self.entities_point.rowCount()
     self.command_stack.beginMacro(
         f"Clone {{Point{row}}} as {{Point{row_count}}}")
     self.command_stack.push(AddTable(self.vpoint_list,
                                      self.entities_point))
     self.command_stack.push(
         EditPointTable(row_count, self.vpoint_list, self.vlink_list,
                        self.entities_point, self.entities_link, args))
     self.command_stack.endMacro()
예제 #10
0
 def set_free_move(self, args: Sequence[Tuple[int, Tuple[float, float,
                                                         float]]]):
     """Free move function."""
     points_text = ", ".join(f"Point{c[0]}" for c in args)
     self.command_stack.beginMacro(f"Moved {{{points_text}}}")
     for row, (x, y, angle) in args:
         arg = self.entities_point.row_data(row)
         arg.x = x
         arg.y = y
         if arg.type != 'R':
             angle_tag = arg.type.split(':')[0]
             arg.type = f"{angle_tag}:{angle:.02f}"
         self.command_stack.push(
             EditPointTable(row, self.vpoint_list, self.vlink_list,
                            self.entities_point, self.entities_link, arg))
     self.command_stack.endMacro()
예제 #11
0
 def __merge_joint(self, index: int, points: Sequence[int]) -> None:
     """Merge the joints into a specific joint."""
     base = points[index]
     self.cmd_stack.beginMacro(
         f"Merge {sorted(points)} based on {{Point{base}}}")
     links = list(self.vpoint_list[base].links)
     args = self.entities_point.row_data(base)
     for p in points:
         if p != base:
             links.extend(set(self.vpoint_list[p].links) - set(links))
     args.links = ','.join(links)
     self.cmd_stack.push(
         EditPointTable(base, self.vpoint_list, self.vlink_list,
                        self.entities_point, self.entities_link, args))
     for p in sorted(points, reverse=True):
         if p != base:
             self.delete_point(p)
     self.cmd_stack.endMacro()
예제 #12
0
    def __set_scale(self) -> None:
        """Scale the mechanism."""
        dlg = _ScaleDialog(self)
        if not dlg.exec_():
            dlg.deleteLater()
            return

        factor = dlg.factor()
        dlg.deleteLater()

        self.command_stack.beginMacro(f"Scale mechanism: {factor}")
        for row in range(self.entities_point.rowCount()):
            args = self.entities_point.row_data(row)
            args.x *= factor
            args.y *= factor
            self.command_stack.push(
                EditPointTable(row, self.vpoint_list, self.vlink_list,
                               self.entities_point, self.entities_link, args))
        self.command_stack.endMacro()