Esempio n. 1
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()
Esempio n. 2
0
    def resolve(self) -> None:
        """Resolve: Using three libraries to solve the system.

        + Pyslvs
        + Python-Solvespace
        + Sketch Solve
        """
        for b, d, a in self.inputs_widget.input_pairs():
            if b == d:
                self.vpoint_list[b].set_offset(a)

        solve_kernel = self.prefer.planar_solver_option
        try:
            if solve_kernel == 0:
                result = expr_solving(
                    self.get_triangle(),
                    {n: f'P{n}'
                     for n in range(len(self.vpoint_list))}, self.vpoint_list,
                    tuple(a for b, d, a in self.inputs_widget.input_pairs()
                          if b != d))
            elif solve_kernel == 1:
                result, _ = _slvs_solve(self.vpoint_list, {
                    (b, d): a
                    for b, d, a in self.inputs_widget.input_pairs()
                } if not self.free_move_button.isChecked() else {})
            elif solve_kernel == 2:
                result = SolverSystem(
                    self.vpoint_list,
                    {(b, d): a
                     for b, d, a in self.inputs_widget.input_pairs()}).solve()
            else:
                raise ValueError("incorrect kernel")
        except ValueError as error:
            # Error: Show warning without update data.
            if self.prefer.console_error_option:
                logger.warn(format_exc())
            error_text = f"Error: {error}"
            self.conflict.setToolTip(error_text)
            self.conflict.setStatusTip(error_text)
            self.conflict.setVisible(True)
            self.dof_view.setVisible(False)
        else:
            self.entities_point.update_current_position(result)
            for i, c in enumerate(result):
                if type(c[0]) is float:
                    self.vpoint_list[i].move(cast(_Coord, c))
                else:
                    c1, c2 = cast(Tuple[_Coord, _Coord], c)
                    self.vpoint_list[i].move(c1, c2)
            self.__dof = vpoint_dof(self.vpoint_list)
            self.dof_view.setText(
                f"{self.__dof} ({self.inputs_widget.input_count()})")
            self.conflict.setVisible(False)
            self.dof_view.setVisible(True)
        self.reload_canvas()
Esempio n. 3
0
    def resolve(self) -> None:
        """Resolve: Using three libraries to solve the system.

        + Pyslvs
        + Python-Solvespace
        + Sketch Solve
        """
        for b, d, a in self.inputs_widget.input_pairs():
            if b == d:
                self.vpoint_list[b].set_offset(a)
        solve_kernel = self.prefer.planar_solver_option
        input_pair = {(b, d): a for b, d, a in self.inputs_widget.input_pairs()}
        try:
            if solve_kernel == Kernel.PYSLVS:
                result = expr_solving(
                    self.get_triangle(),
                    self.vpoint_list,
                    input_pair
                )
            elif solve_kernel == Kernel.SOLVESPACE:
                result, _ = _slvs_solve(
                    self.vpoint_list,
                    input_pair if not self.free_move_button.isChecked() else {}
                )
            elif solve_kernel == Kernel.SKETCH_SOLVE:
                result = SolverSystem(self.vpoint_list, input_pair).solve()
            else:
                raise ValueError("incorrect kernel")
        except ValueError as error:
            # Error: Show warning without update data.
            if self.prefer.console_error_option:
                logger.warn(format_exc())
            error_text = f"Error: {error}"
            self.conflict.setToolTip(error_text)
            self.conflict.setStatusTip(error_text)
            self.conflict.setVisible(True)
            self.dof_view.setVisible(False)
        else:
            self.entities_point.update_current_position(result)
            for i, c in enumerate(result):
                if isinstance(c[0], float):
                    self.vpoint_list[i].move(c)
                else:
                    c1, c2 = c
                    self.vpoint_list[i].move(c1, c2)
            self.__dof = vpoint_dof(self.vpoint_list)
            self.dof_view.setText(
                f"{self.__dof} ({self.inputs_widget.input_count()})")
            self.conflict.setVisible(False)
            self.dof_view.setVisible(True)
        self.reload_canvas()
Esempio n. 4
0
 def test_solving_bfgs(self):
     """Test Sketch Solve kernel."""
     expr, _ = example_list("Jansen's linkage (Single)")
     system = SolverSystem(parse_vpoints(expr), {(0, 1): 0.})
     result = system.solve()
     x, y = result[7]
     self.assertAlmostEqual(-43.170055, x, 6)
     self.assertAlmostEqual(-91.753226, y, 6)
     # Test if angle value changed
     system.set_inputs({(0, 1): 45.})
     result = system.solve()
     x, y = result[7]
     self.assertAlmostEqual(-24.406394, x, 6)
     self.assertAlmostEqual(-91.789596, y, 6)
     # Test if link length changed
     system.set_data({(0, 1): 16.})
     result = system.solve()
     x, y = result[7]
     self.assertAlmostEqual(-24.117994, x, 6)
     self.assertAlmostEqual(-91.198072, y, 6)
Esempio n. 5
0
    def preview_path(self, auto_preview: List[List[Tuple[float, float]]],
                     slider_auto_preview: Dict[int, List[Tuple[float, float]]],
                     vpoints: Sequence[VPoint]):
        """Resolve auto preview path."""
        if not self.right_input():
            auto_preview.clear()
            slider_auto_preview.clear()
            return

        vpoints = tuple(vpoint.copy() for vpoint in vpoints)
        solve_kernel = self.prefer.path_preview_option
        if solve_kernel == len(kernel_list):
            solve_kernel = self.prefer.planar_solver_option
        interval_o = self.inputs_widget.interval()

        # path: [[p]: ((x0, y0), (x1, y1), (x2, y2), ...), ...]
        auto_preview.clear()
        slider_auto_preview.clear()
        for i, vpoint in enumerate(vpoints):
            auto_preview.append([])
            if vpoint.type in {VJoint.P, VJoint.RP}:
                slider_auto_preview[i] = []

        bases = []
        drivers = []
        angles_o = []
        for b, d, a in self.inputs_widget.input_pairs():
            bases.append(b)
            drivers.append(d)
            angles_o.append(a)

        i_count = self.inputs_widget.input_count()
        # Cumulative angle
        angles_cum = [0.] * i_count

        nan = float('nan')
        for interval in (interval_o, -interval_o):
            # Driver pointer
            dp = 0
            angles = angles_o.copy()
            while dp < i_count:
                try:
                    if solve_kernel == 0:
                        result = expr_solving(
                            self.get_triangle(vpoints),
                            {n: f'P{n}'
                             for n in range(len(vpoints))}, vpoints, angles)
                    elif solve_kernel == 1:
                        if self.free_move_button.isChecked():
                            inputs: _Inputs = {}
                        else:
                            inputs = {(bases[i], drivers[i]): angles[i]
                                      for i in range(i_count)}
                        result, _ = _slvs_solve(vpoints, inputs)
                    elif solve_kernel == 2:
                        result = SolverSystem(
                            vpoints, {(bases[i], drivers[i]): angles[i]
                                      for i in range(i_count)}).solve()
                    else:
                        raise ValueError("incorrect kernel")
                except ValueError:
                    # Update with error sign
                    for i in range(len(vpoints)):
                        auto_preview[i].append((nan, nan))
                    # Back to last feasible solution
                    angles[dp] -= interval
                    dp += 1
                else:
                    # Update with result
                    for i, vpoint in enumerate(vpoints):
                        if vpoint.type == VJoint.R:
                            auto_preview[i].append(cast(_Coord, result[i]))
                            vpoint.move(cast(_Coord, result[i]))
                        elif vpoint.type in {VJoint.P, VJoint.RP}:
                            slot, pin = cast(Tuple[_Coord, _Coord], result[i])
                            # Pin path
                            auto_preview[i].append(pin)
                            # Slot path
                            slider_auto_preview[i].append(slot)
                            vpoint.move(slot, pin)
                    angles[dp] += interval
                    angles[dp] %= 360
                    angles_cum[dp] += abs(interval)
                    if angles_cum[dp] > 360:
                        angles[dp] -= interval
                        dp += 1
Esempio n. 6
0
 def preview_path(
     self,
     auto_preview: List[List[Tuple[float, float]]],
     slider_auto_preview: Dict[int, List[Tuple[float, float]]],
     vpoints: Sequence[VPoint]
 ):
     """Resolve auto preview path."""
     auto_preview.clear()
     slider_auto_preview.clear()
     if not self.right_input():
         return
     vpoints = tuple(vpoint.copy() for vpoint in vpoints)
     solve_kernel = self.prefer.path_preview_option
     if solve_kernel == Kernel.SAME_AS_SOLVING:
         solve_kernel = self.prefer.planar_solver_option
     interval = self.inputs_widget.interval()
     # path: [[p]: ((x0, y0), (x1, y1), (x2, y2), ...), ...]
     for i, vpoint in enumerate(vpoints):
         auto_preview.append([])
         if vpoint.type in {VJoint.P, VJoint.RP}:
             slider_auto_preview[i] = []
     input_pair = {(b, d): a for b, d, a in self.inputs_widget.input_pairs()}
     # Cumulative angle
     angles_cum = dict.fromkeys(input_pair, 0.)
     nan = float('nan')
     for dp in input_pair:
         for interval in (interval, -interval):
             while 0 <= angles_cum[dp] <= 360:
                 try:
                     if solve_kernel == Kernel.PYSLVS:
                         result = expr_solving(
                             self.get_triangle(vpoints),
                             vpoints,
                             input_pair
                         )
                     elif solve_kernel == Kernel.SOLVESPACE:
                         result, _ = _slvs_solve(
                             vpoints,
                             {}
                             if self.free_move_button.isChecked() else
                             input_pair
                         )
                     elif solve_kernel == Kernel.SKETCH_SOLVE:
                         result = SolverSystem(vpoints, input_pair).solve()
                     else:
                         raise ValueError("incorrect kernel")
                 except ValueError:
                     # Update with error sign
                     for i in range(len(vpoints)):
                         auto_preview[i].append((nan, nan))
                     # Back to last feasible solution
                     input_pair[dp] -= interval
                     break
                 # Update with result
                 for i, vpoint in enumerate(vpoints):
                     if vpoint.type == VJoint.R:
                         auto_preview[i].append(cast(_Coord, result[i]))
                         vpoint.move(cast(_Coord, result[i]))
                     elif vpoint.type in {VJoint.P, VJoint.RP}:
                         slot, pin = cast(Tuple[_Coord, _Coord], result[i])
                         # Pin path
                         auto_preview[i].append(pin)
                         # Slot path
                         slider_auto_preview[i].append(slot)
                         vpoint.move(slot, pin)
                 angles_cum[dp] += abs(interval)
                 input_pair[dp] += interval
                 input_pair[dp] %= 360
     for path in auto_preview:
         path[:] = path[:-1]