Exemple #1
0
    def __init__(self, mechanism: Dict[str, Any],
                 path: Sequence[Sequence[Tuple[float,
                                               float]]], parent: QWidget):
        """Show the information of results, and setup the preview canvas."""
        super(PreviewDialog, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle(f"Preview: {mechanism['Algorithm']} "
                            f"(max {mechanism['last_gen']} generations)")
        self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)
        self.main_splitter.setSizes([400, 150])
        self.splitter.setSizes([100, 100, 100])
        vpoints = parse_vpoints(mechanism['expression'])
        vlinks = get_vlinks(vpoints)
        preview_widget = _DynamicCanvas(mechanism, path, vpoints, vlinks, self)
        self.left_layout.insertWidget(0, preview_widget)

        labels = []
        for tag, data in chain([('Algorithm', mechanism['Algorithm']),
                                ('time', mechanism['time'])],
                               [(f"P{i}", vpoints[i].c[0])
                                for i in mechanism['placement']]):
            if type(data) is tuple:
                label = f"({data[0]:.02f}, {data[1]:.02f})"
            elif type(data) is float:
                label = f"{data:.02f}"
            else:
                label = f"{data}"
            labels.append(f"{tag}: {label}")
        self.basic_label.setText("\n".join(labels))

        # Algorithm information
        inter = mechanism.get('interrupted', 'N/A')
        if inter == 'False':
            inter_icon = "task_completed.png"
        elif inter == 'N/A':
            inter_icon = "question.png"
        else:
            inter_icon = "interrupted.png"
        if 'last_fitness' in mechanism:
            fitness = f"{mechanism['last_fitness']:.06f}"
        else:
            fitness = 'N/A'
        text_list = [
            f"Max generation: {mechanism.get('last_gen', 'N/A')}",
            f"Fitness: {fitness}",
            f"<img src=\":/icons/{inter_icon}\" width=\"15\"/>"
            f"Interrupted at: {inter}"
        ]
        for k, v in mechanism['settings'].items():
            text_list.append(f"{k}: {v}")
        text = "<br/>".join(text_list)
        self.algorithm_label.setText(
            f"<html><head/><body><p>{text}</p></body></html>")

        # Hardware information
        self.hardware_label.setText("\n".join([
            f"{tag}: {mechanism['hardware_info'][tag]}"
            for tag in ('os', 'memory', 'cpu')
        ]))
Exemple #2
0
def slvs_solve(
    vpoints: Sequence[VPoint],
    inputs: Dict[Tuple[int, int], float]
) -> Tuple[List[Union[_Coord, Tuple[_Coord, _Coord]]], int]:
    """Use element module to convert into solvespace expression."""
    if not vpoints:
        return [], 0

    vlinks: Dict[str, VLink] = {vlink.name: vlink for vlink in get_vlinks(vpoints)}

    # Solvespace kernel
    sys = SolverSystem()
    sys.set_group(1)
    wp = sys.create_2d_base()
    origin_2d = sys.add_point_2d(0., 0., wp)
    sys.dragged(origin_2d, wp)
    origin_2d_p = sys.add_point_2d(10., 0., wp)
    sys.dragged(origin_2d_p, wp)
    hv = sys.add_line_2d(origin_2d, origin_2d_p, wp)
    sys.set_group(2)

    points: List[Entity] = []
    sliders: Dict[int, int] = {}
    slider_bases: List[Entity] = []
    slider_slots: List[Entity] = []

    for i, vpoint in enumerate(vpoints):
        if vpoint.no_link():
            x, y = vpoint.c[0]  # type: float
            point = sys.add_point_2d(x, y, wp)
            sys.dragged(point, wp)
            points.append(point)
            continue

        if vpoint.grounded():
            x, y = vpoint.c[0]
            if vpoint.type in {VJoint.P, VJoint.RP}:
                sliders[i] = len(slider_bases)
                # Base point (slot) is fixed.
                point = sys.add_point_2d(x, y, wp)
                sys.dragged(point, wp)
                slider_bases.append(point)
                # Slot point (slot) is movable.
                x += cos(vpoint.angle)
                y += sin(vpoint.angle)
                slider_slots.append(sys.add_point_2d(x, y, wp))
                # Pin is movable.
                x, y = vpoint.c[1]
                if vpoint.has_offset() and vpoint.true_offset() <= 0.1:
                    if vpoint.offset() > 0:
                        x += 0.1
                        y += 0.1
                    else:
                        x -= 0.1
                        y -= 0.1
                points.append(sys.add_point_2d(x, y, wp))
            else:
                point = sys.add_point_2d(x, y, wp)
                sys.dragged(point, wp)
                points.append(point)
            continue

        x, y = vpoint.c[0]
        point = sys.add_point_2d(x, y, wp)
        if vpoint.type in {VJoint.P, VJoint.RP}:
            sliders[i] = len(slider_bases)
            # Base point (slot) is movable.
            slider_bases.append(point)
            # Slot point (slot) is movable.
            x += cos(vpoint.angle)
            y += sin(vpoint.angle)
            slider_slots.append(sys.add_point_2d(x, y, wp))
            if vpoint.pin_grounded():
                # Pin is fixed.
                x, y = vpoint.c[1]
                point = sys.add_point_2d(x, y, wp)
                sys.dragged(point, wp)
                points.append(point)
            else:
                # Pin is movable.
                x, y = vpoint.c[1]
                if vpoint.has_offset() and vpoint.true_offset() <= 0.1:
                    if vpoint.offset() > 0:
                        x += 0.1
                        y += 0.1
                    else:
                        x -= 0.1
                        y -= 0.1
                points.append(sys.add_point_2d(x, y, wp))
            continue

        # Point is movable.
        points.append(point)

    for vlink in vlinks.values():
        if len(vlink.points) < 2:
            continue
        if vlink.name == 'ground':
            continue

        a = vlink.points[0]
        b = vlink.points[1]
        vp1 = vpoints[a]
        vp2 = vpoints[b]
        if vp1.is_slot_link(vlink.name):
            p1 = slider_bases[sliders[a]]
        else:
            p1 = points[a]
        if vp2.is_slot_link(vlink.name):
            p2 = slider_bases[sliders[b]]
        else:
            p2 = points[b]
        sys.distance(p1, p2, vp1.distance(vp2), wp)

        for c in vlink.points[2:]:  # type: int
            for d in (a, b):
                vp1 = vpoints[c]
                vp2 = vpoints[d]
                if vp1.is_slot_link(vlink.name):
                    p1 = slider_bases[sliders[c]]
                else:
                    p1 = points[c]
                if vp2.is_slot_link(vlink.name):
                    p2 = slider_bases[sliders[d]]
                else:
                    p2 = points[d]
                sys.distance(p1, p2, vp1.distance(vp2), wp)

    for a, b in sliders.items():
        # Base point
        vp1 = vpoints[a]
        p1 = points[a]
        # Base slot
        slider_slot = sys.add_line_2d(slider_bases[b], slider_slots[b], wp)
        if vp1.grounded():
            # Slot is grounded.
            sys.angle(hv, slider_slot, vp1.angle, wp)
            sys.coincident(p1, slider_slot, wp)
            if vp1.has_offset():
                p2 = slider_bases[b]
                if vp1.offset():
                    sys.distance(p2, p1, vp1.offset(), wp)
                else:
                    sys.coincident(p2, p1, wp)
        else:
            # Slider between links.
            for name in vp1.links[:1]:  # type: str
                vlink = vlinks[name]
                # A base link friend.
                c = vlink.points[0]
                if c == a:
                    if len(vlink.points) < 2:
                        # If no any friend.
                        continue
                    c = vlink.points[1]

                vp2 = vpoints[c]
                if vp2.is_slot_link(vlink.name):
                    # c is a slider, and it is be connected with slot link.
                    p2 = slider_bases[sliders[c]]
                else:
                    # c is a R joint or it is not connected with slot link.
                    p2 = points[c]
                sys.angle(
                    slider_slot,
                    sys.add_line_2d(slider_bases[b], p2, wp),
                    vp1.slope_angle(vp2) - vp1.angle,
                    wp
                )
                sys.coincident(p1, slider_slot, wp)

                if vp1.has_offset():
                    p2 = slider_bases[b]
                    if vp1.offset():
                        sys.distance(p2, p1, vp1.offset(), wp)
                    else:
                        sys.coincident(p2, p1, wp)

            if vp1.type != VJoint.P:
                continue

            for name in vp1.links[1:]:
                vlink = vlinks[name]
                # A base link friend.
                c = vlink.points[0]
                if c == a:
                    if len(vlink.points) < 2:
                        # If no any friend.
                        continue
                    c = vlink.points[1]

                vp2 = vpoints[c]
                if vp2.is_slot_link(vlink.name):
                    # c is a slider, and it is be connected with slot link.
                    p2 = slider_bases[sliders[c]]
                else:
                    # c is a R joint or it is not connected with slot link.
                    p2 = points[c]
                sys.angle(
                    slider_slot,
                    sys.add_line_2d(p1, p2, wp),
                    vp1.slope_angle(vp2) - vp1.angle,
                    wp
                )

    for (b, d), angle in inputs.items():
        # The constraints of drive shaft.
        # Simulate the input variables to the mechanism.
        # The 'base points' are shaft center.
        if b == d:
            continue

        vp1 = vpoints[b]
        if vp1.type == VJoint.R:
            p1 = points[b]
        else:
            p1 = slider_bases[sliders[b]]

        angle = radians(angle)
        p2 = sys.add_point_2d(vp1.cx + cos(angle), vp1.cy + sin(angle), wp)
        sys.dragged(p2, wp)
        # The virtual link that dragged by "hand".
        leader = sys.add_line_2d(p1, p2, wp)
        # Make another virtual link that should follow "hand".
        vp2 = vpoints[d]
        if vp2.type == VJoint.R:
            p2 = points[d]
        else:
            p2 = slider_bases[sliders[d]]
        link = sys.add_line_2d(p1, p2, wp)
        sys.angle(link, leader, 0.5, wp)

    # Solve
    result_flag = sys.solve()
    if result_flag == ResultFlag.OKAY:
        result_list = []
        for i, vpoint in enumerate(vpoints):
            p1 = points[i]
            x1, y1 = sys.params(p1.params)
            if vpoint.type == VJoint.R:
                result_list.append((x1, y1))
            else:
                p2 = slider_bases[sliders[i]]
                x2, y2 = sys.params(p2.params)
                result_list.append(((x2, y2), (x1, y1)))
        return result_list, sys.dof()

    if result_flag == ResultFlag.INCONSISTENT:
        error = "inconsistent"
    elif result_flag == ResultFlag.DIDNT_CONVERGE:
        error = "didn't converge"
    else:
        error = "too many unknowns"
    error += f": {sys.faileds()}\n{sys.constraints()}"
    raise ValueError(error)
Exemple #3
0
 def __init__(
     self,
     mechanism: Dict[str, Any],
     path: Sequence[Sequence[_Coord]],
     monochrome: bool,
     parent: QWidget
 ):
     """Show the information of results, and setup the preview canvas."""
     super(PreviewDialog, self).__init__(parent)
     self.setupUi(self)
     self.setWindowTitle(
         f"Preview: {mechanism['algorithm']} "
         f"(max {mechanism['last_gen']} generations)"
     )
     self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)
     for splitter in (self.geo_splitter, self.path_cmp_splitter):
         splitter.setSizes([400, 150])
     self.splitter.setSizes([100, 100, 100])
     vpoints = parse_vpoints(mechanism['expression'])
     vlinks = get_vlinks(vpoints)
     self.canvas1 = _DynamicCanvas(mechanism, path, vpoints, vlinks, self)
     self.canvas2 = _DynamicCanvas(mechanism, path, parent=self)
     for c in (self.canvas1, self.canvas2):
         c.update_pos.connect(self.__set_mouse_pos)
         c.set_monochrome_mode(monochrome)
     self.left_layout.insertWidget(0, self.canvas1)
     self.path_cmp_layout.addWidget(self.canvas2)
     self.plot_joint.addItems(f"P{i}" for i in self.canvas2.get_target())
     labels = []
     for tag, data in chain(
         [(tag, mechanism.get(tag, 'N/A')) for tag in (
             'algorithm', 'time', 'shape_only', 'wavelet_mode')],
         [(f"P{i}", (vpoints[i].c[0, 0], vpoints[i].c[0, 1]))
          for i in mechanism['placement']]
     ):
         if type(data) is tuple:
             label = f"({data[0]:.02f}, {data[1]:.02f})"
         elif type(data) is float:
             label = f"{data:.02f}"
         else:
             label = f"{data}"
         labels.append(f"{tag}: {label}")
     self.basic_label.setText("\n".join(labels))
     # Algorithm information
     inter = mechanism.get('interrupted', 'N/A')
     if inter == 'False':
         inter_icon = "task_completed.png"
     elif inter == 'N/A':
         inter_icon = "question.png"
     else:
         inter_icon = "interrupted.png"
     if 'last_fitness' in mechanism:
         fitness = f"{mechanism['last_fitness']:.06f}"
     else:
         fitness = 'N/A'
     text_list = [
         f"Max generation: {mechanism.get('last_gen', 'N/A')}",
         f"Fitness: {fitness}",
         f"<img src=\":/icons/{inter_icon}\" width=\"15\"/>"
         f"Interrupted at: {inter}"
     ]
     for k, v in mechanism['settings'].items():
         text_list.append(f"{k}: {v}")
     text = "<br/>".join(text_list)
     self.algorithm_label.setText(f"<html><p>{text}</p></html>")
     # Hardware information
     self.hardware_label.setText("\n".join([
         f"{tag}: {mechanism['hardware_info'][tag]}"
         for tag in ('os', 'memory', 'cpu')
     ]))
Exemple #4
0
def _slvs_solve(
    vpoints: Sequence[VPoint], inputs: Dict[Tuple[int, int], float]
) -> Tuple[List[Union[_Coord, Tuple[_Coord, _Coord]]], int]:
    """Use element module to convert into Solvespace expression."""
    if not vpoints:
        return [], 0
    # VLinks with strings
    vlinks = {}
    for vlink in get_vlinks(vpoints):
        vlinks[vlink.name] = vlink
    # Solvespace kernel
    sys = PySolver()
    sys.set_group(1)
    wp = sys.create_2d_base()
    origin_2d = sys.add_point_2d(0., 0., wp)
    sys.dragged(origin_2d, wp)
    origin_2d_p = sys.add_point_2d(10., 0., wp)
    sys.dragged(origin_2d_p, wp)
    hv = sys.add_line_2d(origin_2d, origin_2d_p, wp)
    sys.set_group(2)

    points: List[Entity] = []
    sliders: Dict[int, int] = {}
    slider_bases: List[Entity] = []
    slider_slots: List[Entity] = []
    for i, vpoint in enumerate(vpoints):
        if vpoint.no_link():
            x, y = vpoint.c[0]
            point = sys.add_point_2d(x, y, wp)
            sys.dragged(point, wp)
            points.append(point)
            continue
        if vpoint.grounded():
            x, y = vpoint.c[0]
            if vpoint.type in {VJoint.P, VJoint.RP}:
                sliders[i] = len(slider_bases)
                # Base point (slot) is fixed
                point = sys.add_point_2d(x, y, wp)
                sys.dragged(point, wp)
                slider_bases.append(point)
                # Slot point (slot) is movable
                x += cos(vpoint.angle)
                y += sin(vpoint.angle)
                slider_slots.append(sys.add_point_2d(x, y, wp))
                # Pin is movable
                x, y = _offset(vpoint)
                points.append(sys.add_point_2d(x, y, wp))
            else:
                point = sys.add_point_2d(x, y, wp)
                sys.dragged(point, wp)
                points.append(point)
            continue
        x, y = vpoint.c[0]
        point = sys.add_point_2d(x, y, wp)
        if vpoint.type in {VJoint.P, VJoint.RP}:
            sliders[i] = len(slider_bases)
            # Base point (slot) is movable
            slider_bases.append(point)
            # Slot point (slot) is movable
            x += cos(vpoint.angle)
            y += sin(vpoint.angle)
            slider_slots.append(sys.add_point_2d(x, y, wp))
            if vpoint.pin_grounded():
                # Pin is fixed
                x, y = vpoint.c[1]
                point = sys.add_point_2d(x, y, wp)
                sys.dragged(point, wp)
                points.append(point)
            else:
                # Pin is movable
                x, y = _offset(vpoint)
                points.append(sys.add_point_2d(x, y, wp))
            continue
        # Point is movable
        points.append(point)

    def pick_slider(i1: int, i2: int) -> Tuple[Entity, Entity, float]:
        n1 = vpoints[i1]
        n2 = vpoints[i2]
        if n1.is_slot_link(vlink.name):
            e1 = slider_bases[sliders[i1]]
        else:
            e1 = points[i1]
        if n2.is_slot_link(vlink.name):
            e2 = slider_bases[sliders[i2]]
        else:
            e2 = points[i2]
        return e1, e2, n1.distance(n2)

    for vlink in vlinks.values():
        if len(vlink.points) < 2:
            continue
        if vlink.name == VLink.FRAME:
            continue
        a = vlink.points[0]
        b = vlink.points[1]
        p1, p2, d = pick_slider(a, b)
        sys.distance(p1, p2, d, wp)
        for c in vlink.points[2:]:
            for d in (a, b):
                p1, p2, x = pick_slider(c, d)
                sys.distance(p1, p2, x, wp)

    def get_friend(group: VLink, base: int) -> Optional[Tuple[VPoint, Entity]]:
        """Get friend for slider."""
        # A base link friend
        index = group.points[0]
        if index == base:
            if len(group.points) < 2:
                # If no any friend
                return None
            index = group.points[1]
        vp = vpoints[index]
        if vp.is_slot_link(group.name):
            # c is a slider, and it is be connected with slot link.
            return vp, slider_bases[sliders[index]]
        else:
            # c is a R joint or it is not connected with slot link.
            return vp, points[index]

    for a, b in sliders.items():
        # Base point
        vp1 = vpoints[a]
        p1 = points[a]
        # Base slot
        slider_slot = sys.add_line_2d(slider_bases[b], slider_slots[b], wp)
        if vp1.grounded():
            # Slot is grounded
            sys.angle(hv, slider_slot, vp1.angle, wp)
            sys.coincident(p1, slider_slot, wp)
            if vp1.has_offset():
                p2 = slider_bases[b]
                if vp1.offset():
                    sys.distance(p2, p1, vp1.offset(), wp)
                else:
                    sys.coincident(p2, p1, wp)
        else:
            # Slider between links
            for name in vp1.links[:1]:
                vlink = vlinks[name]
                ret = get_friend(vlink, a)
                if ret is None:
                    continue
                vp2, p2 = ret
                sys.angle(slider_slot, sys.add_line_2d(slider_bases[b], p2,
                                                       wp),
                          vp1.slope_angle(vp2) - vp1.angle, wp)
                sys.coincident(p1, slider_slot, wp)
                if vp1.has_offset():
                    p2 = slider_bases[b]
                    if vp1.offset():
                        sys.distance(p2, p1, vp1.offset(), wp)
                    else:
                        sys.coincident(p2, p1, wp)
            if vp1.type != VJoint.P:
                continue
            for name in vp1.links[1:]:
                vlink = vlinks[name]
                ret = get_friend(vlink, a)
                if ret is None:
                    continue
                vp2, p2 = ret
                sys.angle(slider_slot, sys.add_line_2d(p1, p2, wp),
                          vp1.slope_angle(vp2) - vp1.angle, wp)
    for (b, d), angle in inputs.items():
        # The constraints of drive shaft
        # Simulate the input variables to the mechanism
        # The 'base points' are shaft center
        if b == d:
            continue
        vp1 = vpoints[b]
        if vp1.type == VJoint.R:
            p1 = points[b]
        else:
            p1 = slider_bases[sliders[b]]
        angle = radians(angle)
        p2 = sys.add_point_2d(vp1.cx + cos(angle), vp1.cy + sin(angle), wp)
        sys.dragged(p2, wp)
        # The virtual link that dragged by "hand".
        leader = sys.add_line_2d(p1, p2, wp)
        # Make another virtual link that should follow "hand".
        vp2 = vpoints[d]
        if vp2.type == VJoint.R:
            p2 = points[d]
        else:
            p2 = slider_bases[sliders[d]]
        link = sys.add_line_2d(p1, p2, wp)
        sys.angle(link, leader, 0.5, wp)
    # Solve
    result_flag = sys.solve()
    if result_flag == ResultFlag.OKAY:
        result_list: List[Union[_Coord, Tuple[_Coord, _Coord]]] = []
        for i, vpoint in enumerate(vpoints):
            p1 = points[i]
            x1, y1 = sys.params(p1.params)
            if vpoint.type == VJoint.R:
                result_list.append((x1, y1))
            else:
                p2 = slider_bases[sliders[i]]
                x2, y2 = sys.params(p2.params)
                result_list.append(((x2, y2), (x1, y1)))
        return result_list, sys.dof()
    if result_flag == ResultFlag.INCONSISTENT:
        error = "inconsistent"
    elif result_flag == ResultFlag.DIDNT_CONVERGE:
        error = "didn't converge"
    else:
        error = "too many unknowns"
    raise ValueError(f"{error}: {sys.failures()}\n{sys.constraints()}")