示例#1
0
    def __copy(self):
        """Ask a name to copy a data."""
        row = self.collections_list.currentRow()
        if not row > -1:
            return

        name, ok = QInputDialog.getText(
            self,
            "Profile name",
            "Please enter a new profile name:"
        )
        if not ok:
            return

        if not name:
            QMessageBox.warning(
                self,
                "Profile name",
                "Can not use blank string to rename."
            )
            return

        name_old = self.collections_list.item(row).text()
        self.collections[name] = self.collections[name_old].copy()
        self.collections_list.addItem(name)
        self.unsave_func()
示例#2
0
 def pasteStorage(self):
     """Add the storage data from string."""
     expr, ok = QInputDialog.getMultiLineText(self, "Storage",
                                              "Please input expression:")
     if not ok:
         return
     try:
         # Put the expression into parser to see if it is legal.
         parse_params(expr)
     except Exception as e:
         print(e)
         QMessageBox.warning(self, "Loading failed",
                             "Your expression is in an incorrect format.")
         return
     name, ok = QInputDialog.getText(self, "Storage",
                                     "Please input name tag:")
     if not ok:
         return
     name_list = [
         self.mechanism_storage.item(i).text()
         for i in range(self.mechanism_storage.count())
     ]
     i = 0
     name = name or f"Prototype_{i}"
     while name in name_list:
         name = f"Prototype_{i}"
         i += 1
     self.__add_storage(name, expr)
示例#3
0
    def __rename(self):
        """Show up a string input to change the data name."""
        row = self.collections_list.currentRow()
        if not row > -1:
            return

        name, ok = QInputDialog.getText(
            self,
            "Profile name",
            "Please enter the profile name:"
        )
        if not ok:
            return

        if not name:
            QMessageBox.warning(
                self,
                "Profile name",
                "Can not use blank string to rename."
            )
            return

        item = self.collections_list.item(row)
        self.collections[name] = self.collections.pop(item.text())
        item.setText(name)
        self.unsave_func()
示例#4
0
 def on_expression_auto_clicked(self):
     """Auto configure the solutions."""
     if not self.driver_list.count():
         QMessageBox.information(self, "Auto configure",
                                 "Please setting the driver joint(s).")
         return
     reply = QMessageBox.question(
         self, "Auto configure", "This function can detect the structure " +
         "to configure the solutions.\n" +
         "The current settings will be cleared.")
     if ((reply != QMessageBox.Yes)
             or (not self.on_expression_clear_clicked())):
         return
     exprs = vpoints_configure(
         graph2vpoints(self.PreviewWindow.G, self.PreviewWindow.pos,
                       self.PreviewWindow.cus, self.PreviewWindow.same), [
                           eval(item.text().replace('P', ''))
                           for item in list_items(self.driver_list)
                       ], self.PreviewWindow.status)
     for expr in exprs:
         self.__addSolution(*expr)
     self.__hasSolution()
     self.__setWarning(self.expression_list_label,
                       not self.PreviewWindow.isAllLock())
     self.PreviewWindow.update()
示例#5
0
    def refresh_proj(self, node: Optional[QTreeWidgetItem] = None):
        """Re-parse the file node."""
        if node is None:
            node = self.tree_main.currentItem()
        if not node.text(1):
            QMessageBox.warning(self, "No path",
                                "Can only refresh from valid path.")
            return

        self.__delete_node_data(node)
        node.takeChildren()
        parse(node, self.data)
        self.tree_main.setCurrentItem(node)
        _expand_recursive(node)
        code = int(node.text(2))
        self.text_editor.setText(self.data[code])
        self.data.set_saved(code, True)
        self.__add_macros()

        # File keeper
        if self.keeper is not None:
            self.keeper.stop()
        self.keeper = FileKeeper(LOADED_FILES, self)
        self.keeper.file_changed.connect(self.file_changed_warning)
        self.keeper.start()
示例#6
0
 def on_match_button_clicked(self):
     """Fitting function."""
     l = len(self.path)
     if l==0:
         return
     index = list(range(l))
     
     def polyfit(x: Sequence[float], y: Sequence[float], d: int):
         """Return a 2D fitting equation."""
         coeffs = np.polyfit(x, y, d)
         #Fit values and mean.
         yhat = np.poly1d(coeffs)(x)
         ybar = np.sum(y)/len(y)
         return (
             lambda t: sum(c * t**pow for pow, c in enumerate(reversed(coeffs))),
             np.sum((yhat - ybar)**2) / np.sum((y - ybar)**2)
         )
     
     x_func, x_accuracy = polyfit(index, [x for x, y in self.path], 4)
     y_func, y_accuracy = polyfit(index, [y for x, y in self.path], 4)
     QMessageBox.information(self,
         "Curve fitting",
         "Accuracy:\nx: {:.02f}%\ny: {:.02f}%".format(x_accuracy, y_accuracy),
         QMessageBox.Ok,
         QMessageBox.Ok
     )
     m = self.match_num.value()
     self.r_path = [(x_func(i/m*l), y_func(i/m*l)) for i in range(m)]
     self.accept()
示例#7
0
    def __read_slvs(self, file_name: str):
        """Read slvs format.

        + Choose a group.
        + Read the entities of the group.
        """
        parser = SlvsParser(file_name)
        if not parser.isValid():
            QMessageBox.warning(self, "Format error",
                                "The format is not support.")
            return
        groups = parser.getGroups()
        if not groups:
            QMessageBox.warning(self, "Format error",
                                "The model file is empty.")
            return
        group, ok = QInputDialog.getItem(
            self, "Solvespace groups", "Choose a group:\n"
            "(Please know that the group must contain a sketch only.)",
            ["@".join(g) for g in groups], 0, False)
        if not ok:
            return
        self.clear()
        self.DatabaseWidget.reset()
        print(f"Read from group: {group}")
        self.parseExpression(parser.parse(group.split('@')[0]))
示例#8
0
    def __replace_project(self):
        """Replace in project."""
        self.__find_project()
        count = self.find_list.count()
        if count == 0:
            return

        if QMessageBox.question(self, "Replace in project",
                                f"Replace all? ({count})") != QMessageBox.Yes:
            return

        replace_text = self.replace_bar.text()
        if not replace_text:
            if QMessageBox.question(
                    self, "Empty replace text",
                    f"Replace text is an empty string, still replace all?"
            ) != QMessageBox.No:
                return

        text, replace_text, flags = self.__search_option()

        used_code = set()
        for row in range(self.find_list.count()):
            code = int(self.find_list.item(row).toolTip().split(':')[0])
            if code in used_code:
                continue
            self.data[code] = re.sub(text, replace_text, self.data[code],
                                     flags)
            used_code.add(code)

        self.__root_unsaved()
示例#9
0
    def __add_from_files(self):
        """Append atlas by text files."""
        file_names = self.input_from("Edges data", ["Text File (*.txt)"],
                                     multiple=True)
        if not file_names:
            return

        read_data = []
        for file_name in file_names:
            with open(file_name, 'r', encoding='utf-8') as f:
                for line in f:
                    read_data.append(line)

        collections = []
        for edges in read_data:
            try:
                collections.append(Graph(eval(edges)))
            except (SyntaxError, TypeError):
                QMessageBox.warning(self, "Wrong format",
                                    "Please check the edges text format.")
                return
        if not collections:
            return
        self.collections += collections
        self.__reload_atlas()
示例#10
0
 def __import_xlsx(self):
     """Paste path data from a Excel file."""
     file_name = self.input_from(
         "Excel file",
         ["Microsoft Office Excel (*.xlsx *.xlsm *.xltx *.xltm)"])
     if not file_name:
         return
     wb = load_workbook(file_name)
     ws = wb.get_sheet_by_name(wb.get_sheet_names()[0])
     data = []
     # Keep finding until there is no value.
     i = 1
     while True:
         x = ws.cell(row=i, column=1).value
         y = ws.cell(row=i, column=2).value
         if None in {x, y}:
             break
         try:
             data.append((round(float(x), 4), round(float(y), 4)))
         except (IndexError, AttributeError):
             QMessageBox.warning(
                 self, "File error", "Wrong format.\n"
                 "The data sheet seems to including non-digital cell.")
             break
         i += 1
     for x, y in data:
         self.add_point(x, y)
示例#11
0
    def __find_project(self):
        """Find in all project."""
        self.find_list.clear()
        self.find_list_node.clear()
        node_current = self.tree_main.currentItem()
        if node_current is None:
            return

        root = _get_root(node_current)
        text, _, flags = self.__search_option()

        def find_in_nodes(node: QTreeWidgetItem, last_name: str = ''):
            """Find the word in all nodes."""
            last_name += node.text(0)
            if node.childCount():
                last_name += '->'
            code = int(node.text(2))
            doc = self.data[code]
            pattern = re.compile(text.encode('utf-8'), flags)
            for m in pattern.finditer(doc.encode('utf-8')):
                start, end = m.span()
                item = QListWidgetItem(last_name)
                item.setToolTip(f"{code}:{start}:{end}")
                self.find_list_node[code] = node
                self.find_list.addItem(item)
            for i in range(node.childCount()):
                find_in_nodes(node.child(i), last_name)

        find_in_nodes(root)
        find_in_nodes = None
        count = self.find_list.count()
        QMessageBox.information(self, "Find in project",
                                f"Found {count} result.")
示例#12
0
def on_mechanism_storage_paste_clicked(self):
    """Add the storage data from string."""
    expr, ok = QInputDialog.getText(self, "Storage",
                                    "Please input expression:")
    if not ok:
        return
    try:
        #Put the expression into parser to see if it is legal.
        PMKS_parser.parse(expr)
    except:
        QMessageBox.warning(self, "Loading failed",
                            "Your expression is in an incorrect format.")
        return
    name, ok = QInputDialog.getText(self, "Storage", "Please input name tag:")
    if not ok:
        return
    if not name:
        nameList = [
            self.mechanism_storage.item(i).text()
            for i in range(self.mechanism_storage.count())
        ]
        i = 0
        while "Prototype_{}".format(i) in nameList:
            i += 1
        name = "Prototype_{}".format(i)
    _addStorage(self, name, expr, clear=False)
示例#13
0
def on_action_Import_PMKS_server_triggered(self):
    """Load PMKS URL and turn it to expression."""
    URL, ok = QInputDialog.getText(self, "PMKS URL input",
                                   "Please input link string:")
    if not ok:
        return
    if not URL:
        QMessageBox.warning(self, "Loading failed",
                            "Your link is in an incorrect format.")
        return
    try:
        for s in URL.split('?')[-1].split('&'):
            if 'mech=' in s:
                expr = s.replace('mech=', '').split('|')
                break
        textList = [s for s in expr if s not in ('', " ", '\n')]
        expression = []
        while textList:
            item = textList.pop(0).split(',')[:-1]
            for i, e in enumerate(reversed(item)):
                if e in ['R', 'P', 'RP']:
                    t = -(i + 1)
                    break
            links = item[:t]
            item = item[t:]
            expression.append("J[{}, P[{}], L[{}]]".format(
                "{}:{}".format(item[0], item[-1]) if item[0] != 'R' else 'R',
                ", ".join((item[1], item[2])), ", ".join(links)))
        expression = "M[{}]".format(", ".join(expression))
    except:
        QMessageBox.warning(self, "Loading failed",
                            "Your link is in an incorrect format.")
    else:
        self.parseExpression(expression)
示例#14
0
 def parse_expression(self, expr: str):
     """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[0].split(',')
             link_names = {
                 vlink.name for vlink in self.entities_link.data()
             }
             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.entities_point))
             self.command_stack.push(EditPointTable(
                 row_count,
                 self.entities_point,
                 self.entities_link,
                 args
             ))
             self.command_stack.endMacro()
示例#15
0
 def on_importXLSX_clicked(self):
     """Paste path data from a Excel file."""
     fileName = self.inputFrom(
         "Excel file",
         ["Microsoft Office Excel (*.xlsx *.xlsm *.xltx *.xltm)"]
     )
     if not fileName:
         return
     wb = openpyxl.load_workbook(fileName)
     ws = wb.get_sheet_by_name(wb.get_sheet_names()[0])
     data = []
     #Keep finding until there is no value.
     i = 1
     while True:
         x = ws.cell(row=i, column=1).value
         y = ws.cell(row=i, column=2).value
         if x == None or y == None:
             break
         try:
             data.append((round(float(x), 4), round(float(y), 4)))
         except:
             QMessageBox.warning(self,
                 "File error",
                 "Wrong format.\n" +
                 "The datasheet seems to including non-digital cell."
             )
             break
         i += 1
     for x, y in data:
         self.add_point(x, y)
示例#16
0
 def on_Edges_to_altas_clicked(self):
     """Turn the text files into a atlas image.
     
     This opreation will load all edges to list widget first.
     """
     fileNames = self.inputFrom(
         "Edges data",
         ["Text File (*.txt)"],
         multiple=True
     )
     if not fileNames:
         return
     read_data = []
     for fileName in fileNames:
         with open(fileName, 'r') as f:
             read_data += f.read().split('\n')
     answer = []
     for edges in read_data:
         try:
             answer.append(Graph(eval(edges)))
         except:
             QMessageBox.warning(self,
                 "Wrong format",
                 "Please check the edges text format."
             )
             return
     if not answer:
         return
     self.answer = answer
     self.on_reload_atlas_clicked()
     check_status = self.save_edges_auto.isChecked()
     self.save_edges_auto.setChecked(False)
     self.on_save_atlas_clicked()
     self.save_edges_auto.setChecked(check_status)
示例#17
0
    def __match(self):
        """Fitting function."""
        length = len(self.path)
        if length == 0:
            return
        index = list(range(length))

        def poly_fit(x: List[float], y: List[float], d: int):
            """Return a 2D fitting equation."""
            coefficient = np.polyfit(x, y, d)
            # Fit values and mean.
            y_hat = np.poly1d(coefficient)(x)
            y_bar = np.sum(y) / len(y)

            def func(t: float) -> float:
                """Return y(x) function."""
                return sum(c * t**p
                           for p, c in enumerate(reversed(coefficient)))

            yh_yb = y_hat - y_bar
            y_yb = y - y_bar
            return func, np.sum(yh_yb * yh_yb) / np.sum(y_yb * y_yb)

        x_func, x_accuracy = poly_fit(index, [x for x, y in self.path], 4)
        y_func, y_accuracy = poly_fit(index, [y for x, y in self.path], 4)
        QMessageBox.information(
            self, "Curve fitting",
            f"Accuracy:\nx: {x_accuracy:.02f}%\ny: {y_accuracy:.02f}%")
        m = self.match_num.value()
        self.r_path = [(x_func(i / m * length), y_func(i / m * length))
                       for i in range(m)]
        self.accept()
示例#18
0
 def saveReplyBox(self, title: str, file_name: str):
     """Show message when successfully saved."""
     size = QFileInfo(file_name).size()
     print("Size: " + (f"{size / 1024 / 1024:.02f} MB" if size / 1024 //
                       1024 else f"{size / 1024:.02f} KB"))
     QMessageBox.information(self, f"Initial Saved: {title}",
                             f"Successfully saved:\n{file_name}")
     print(f"Initial saved: [\"{file_name}\"]")
示例#19
0
 def __save_picture_clipboard(self):
     """Capture the canvas image to clipboard."""
     QApplication.clipboard().setPixmap(self.main_canvas.grab())
     QMessageBox.information(
         self,
         "Captured!",
         "Canvas widget picture is copy to clipboard."
     )
示例#20
0
 def __about(self):
     """Kmol editor about."""
     QMessageBox.about(self, "About Kmol Editor", '\n'.join(INFO + (
         '',
         "Author: " + __author__,
         "Email: " + __email__,
         __copyright__,
         "License: " + __license__,
     )))
示例#21
0
def saveReplyBox(self, title: str, file_name: str):
    """Show message when successfully saved."""
    size = QFileInfo(file_name).size()
    print("Size: {}".format("{} MB".format(round(size / 1024 /
                                                 1024, 2)) if size / 1024 //
                            1024 else "{} KB".format(round(size / 1024, 2))))
    QMessageBox.information(self, title,
                            "Successfully converted:\n{}".format(file_name))
    print("Successful saved: [\"{}\"]".format(file_name))
示例#22
0
 def loadCommitID(self, id: int):
     """Check the id is correct."""
     try:
         commit = self.history_commit.where(CommitModel.id == id).get()
     except CommitModel.DoesNotExist:
         QMessageBox.warning(self, "Warning", "Commit ID is not exist.")
     except AttributeError:
         QMessageBox.warning(self, "Warning", "Nothing submitted.")
     else:
         self.loadCommit(commit)
示例#23
0
 def add_collection(self, edges: Sequence[Tuple[int, int]]):
     """Add collection by in put edges."""
     graph = Graph(edges)
     error = self.__is_valid_graph(graph)
     if error:
         QMessageBox.warning(self, "Add Collection Error",
                             f"Error: {error}")
         return
     self.collections.append(graph)
     self.unsaveFunc()
     self.__reload_atlas()
示例#24
0
 def on_Expression_auto_clicked(self):
     """Auto configure the solutions."""
     if not self.Driver_list.count():
         QMessageBox.information(self, "Auto configure",
                                 "Please setting the driver joint(s).")
         return
     reply = QMessageBox.question(
         self, "Auto configure",
         "This function can detect the structure to configure the solutions.\n"
         + "The current settings will be cleared.")
     if reply == QMessageBox.Yes and self.on_Expression_clear_clicked():
         self.auto_configure_expression()
示例#25
0
 def refresh_proj(self):
     """Re-parse the file node."""
     node = self.tree_main.currentItem()
     if not node.text(1):
         QMessageBox.warning(
             self,
             "No path",
             "Can only refresh from valid path."
         )
     parse(node, self.data)
     self.tree_main.setCurrentItem(node)
     self.text_editor.setText(self.data[int(node.text(2))])
示例#26
0
 def __readPathFromCSV(self, data: List[str]):
     """Trun STR to FLOAT then add them to current target path."""
     try:
         data = [(round(float(data[i]), 4), round(float(data[i + 1]), 4))
                 for i in range(0, len(data), 2)]
     except:
         QMessageBox.warning(
             self, "File error",
             "Wrong format.\nIt should be look like this:" +
             "\n0.0,0.0[\\n]" * 3)
     else:
         for e in data:
             self.addPoint(e[0], e[1])
示例#27
0
 def __read_path_from_csv(self, raw_data: List[str]):
     """Turn string to float then add them to current target path."""
     try:
         data = [(round(float(raw_data[i]),
                        4), round(float(raw_data[i + 1]), 4))
                 for i in range(0, len(raw_data), 2)]
     except (IndexError, ValueError):
         QMessageBox.warning(
             self, "File error",
             "Wrong format.\nIt should be look like this:" +
             ("\n0.0,0.0[\\n]" * 3))
     else:
         for x, y in data:
             self.add_point(x, y)
示例#28
0
 def __from_canvas(self):
     """Get a collection data from current mechanism."""
     try:
         collection = self.getCollection()
     except ValueError as e:
         QMessageBox.warning(self, "Mechanism not support.", str(e))
     else:
         num = 0
         name = f"mechanism{num}"
         while name in self.collections:
             name = f"mechanism{num}"
             num += 1
         self.collections[name] = collection.copy()
         self.collections_list.addItem(name)
示例#29
0
    def __import_pmks_url(self):
        """Load PMKS URL and turn it to expression."""
        url, ok = QInputDialog.getText(
            self,
            "PMKS URL input",
            "Please input link string:"
        )
        if not ok:
            return
        if not url:
            QMessageBox.warning(
                self,
                "Loading failed",
                "Your link is in an incorrect format."
            )
            return
        try:
            for s in url.split('?')[-1].split('&'):
                if 'mech=' in s:
                    expr = s.replace('mech=', '').split('|')
                    break
            else:
                raise ValueError

            text_list = [s for s in expr if s not in ('', " ", '\n')]
            expr.clear()
            while text_list:
                item = text_list.pop(0).split(',')[:-1]
                for i, e in enumerate(reversed(item)):
                    if e in {'R', 'P', 'RP'}:
                        t = -(i + 1)
                        break
                else:
                    raise ValueError
                links = item[:t]
                item = item[t:]
                type_text = f"{item[0]}:{item[-1]}" if item[0] != 'R' else 'R'
                links_text = ", ".join(links)
                expr.append(f"J[{type_text}, P[{item[1]}, {item[2]}], L[{links_text}]]")
            expr = "M[" + ", ".join(expr) + "]"
        except (ValueError, IndexError):
            QMessageBox.warning(
                self,
                "Loading failed",
                "Your link is in an incorrect format."
            )
        else:
            self.parse_expression(expr)
示例#30
0
 def on_clear_button_clicked(self):
     if self.profile_name.text() == "No setting":
         return
     reply = QMessageBox.question(self, "Clear setting",
                                  "Do you want to clear the setting?")
     if reply == QMessageBox.Yes:
         self.__clearSettings()