From 8a9933e4decb3b6a57b47b6409474bd476920c24 Mon Sep 17 00:00:00 2001 From: Hong-Phuc Bui <hong-phuc.bui@htwsaar.de> Date: Fri, 27 Sep 2024 01:22:49 +0200 Subject: [PATCH] demo show image --- /dev/null | 251 ------------------- image-demo/README.md | 20 + image-demo/src/imgdemo/ui_mainwindow.py | 111 ++++++++ stundenplan/src/pygraph/graphdemo.py | 18 stundenplan/src/pygraph/shortestpath.py | 53 ++++ image-demo/src/imgdemo/__init__.py | 0 image-demo/pyproject.toml | 19 + stundenplan/tests/pygraph/shortestpath_tests.py | 53 +++ bit_op_numpy_example.py | 41 +++ image-demo/src/imgdemo/guimain.py | 74 +++++ image-demo/src/imgdemo/mainwindow.ui | 107 ++++++++ 11 files changed, 475 insertions(+), 272 deletions(-) diff --git a/bit_op_numpy_example.py b/bit_op_numpy_example.py new file mode 100644 index 0000000..c80d8bb --- /dev/null +++ b/bit_op_numpy_example.py @@ -0,0 +1,41 @@ +import numpy as np + +def print_binary_pattern_32(x): + pattern = bin(x)[2:].zfill(32) + print(x, ':', pattern[0:8], pattern[9:16], pattern[17:24], pattern[25:], len(pattern)) + +def to32_np_fn(x: list[np.uint8,np.uint8,np.uint8,np.uint8]): + y = np.left_shift(x, [np.uint32(0), np.uint32(8), np.uint32(16), np.uint32(24)]) + return y[0] | y[1] | y[2] | y[3] + + +def to32_bit_op(x: list[np.uint8,np.uint8,np.uint8,np.uint8]): + # 1 0000_0000 0000_0000 0000_0000 0000_0000 + mask = (2**32) | (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0]) + # remove the most significant bit + return mask & (2**32-1) + + +def quaternary_8bit_to_unary_32bit(data, to32_fn): + four_group = np.array(data, dtype=np.uint8).reshape((-1, 4)) + return np.array([to32_fn(x) for x in four_group]) + + + +if __name__ == '__main__': + raw_data = [255, 0, 15, 170, + 0b101, 0b1100, 0b1001101, 0b1000_0000, + 9, 10, 11, 0b1000_0000] + + print(f"Konvertierung jeweiliger 4er-Tuple in einem uint32") + print() + print("Mit Python built-int Left-Shift-Operator") + result = quaternary_8bit_to_unary_32bit(raw_data, to32_np_fn) + for r in result: + print_binary_pattern_32(r) + + print() + print("Mit numpy left_shift Funktion") + result = quaternary_8bit_to_unary_32bit(raw_data, to32_bit_op) + for r in result: + print_binary_pattern_32(r) \ No newline at end of file diff --git a/image-demo/README.md b/image-demo/README.md new file mode 100644 index 0000000..da86bd4 --- /dev/null +++ b/image-demo/README.md @@ -0,0 +1,20 @@ +# Demonstration von Zusammenspiel numpy/PIL und PySide6 + +## Build python file from ui + +```shell +pyside6-project build imgdemo.json +``` + +## Install as development mode (editable) + +``` +pip install -e . +``` + +## Run the application after install + + +``` +imgdemo +``` \ No newline at end of file diff --git a/image-demo/pyproject.toml b/image-demo/pyproject.toml new file mode 100644 index 0000000..4f2fb7d --- /dev/null +++ b/image-demo/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "image-demo" +version = "0.0.1" +dependencies = [ + "numpy >= 2.0.0", + "matplotlib >= 3.9", + "PySide6 >= 6.7" +] + +[tool.setuptools.packages.find] +# All the following settings are optional: +where = ["src"] + +[project.gui-scripts] +imgdemo = "imgdemo.guimain:main" diff --git a/image-demo/src/imgdemo/__init__.py b/image-demo/src/imgdemo/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/image-demo/src/imgdemo/__init__.py diff --git a/image-demo/src/imgdemo/guimain.py b/image-demo/src/imgdemo/guimain.py new file mode 100644 index 0000000..665f312 --- /dev/null +++ b/image-demo/src/imgdemo/guimain.py @@ -0,0 +1,74 @@ +import sys + +from PySide6.QtGui import QPixmap, QImage +#from PIL.ImageQt import QPixmap, QImage + +from PySide6.QtWidgets import QApplication, QMainWindow, QFileDialog +import numpy as np +from PIL import Image + +from imgdemo.ui_mainwindow import Ui_MainWindow + +class MainWindow(QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + self.saved_file = ('', '') + self.chosen_file = ('', '') + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + self.ui.actionChoose_Image.triggered.connect(self.choose_image) + self.ui.actionSave_Image.triggered.connect(self.save_image) + + def choose_image(self): + self.chosen_file = ('', '') # reset (for safe) + self.chosen_file = QFileDialog.getOpenFileName(None, "Choose Image", "", + "Images (*.png *.xpm *.jpg *.tiff) ;; All Filetypes (*.*)") + print(self.chosen_file) + if self.chosen_file[0] != '': # user has chosen a file + self.display_image() + + + def save_image(self): + self.saved_file = ('', '') # reset for safe + self.saved_file = QFileDialog.getSaveFileName(None, "Choose Image", "", + "All (*.*)") + print(self.saved_file) + + + def display_image(self): + pixmap = QPixmap(self.chosen_file[0]) + self.ui.origin_img.setPixmap(pixmap) + # now read the image and show it via Image in other container + with Image.open(self.chosen_file[0]) as img: + image = np.asarray(img, dtype=np.uint8) + self.display_numpy_image(image) + + + def display_numpy_image(self, image): + height, width, channel = image.shape + print(height, width, channel) + + bytes_per_line = channel * width # color + img_format = QImage.Format.Format_RGBX8888 + if channel == 4: + img_format = QImage.Format.Format_ARGB32 + elif channel == 3: + img_format = QImage.Format.Format_RGB888 + qImg = QImage(image.data, width, height, bytes_per_line, img_format).rgbSwapped() + pixmap = QPixmap(qImg) + self.ui.result_img.setPixmap(pixmap) + + + + +def main(): + app = QApplication(sys.argv) + window = MainWindow() + window.show() + + sys.exit(app.exec()) + pass + + +if __name__ == "__main__": + main() diff --git a/image-demo/src/imgdemo/mainwindow.ui b/image-demo/src/imgdemo/mainwindow.ui new file mode 100644 index 0000000..f0db623 --- /dev/null +++ b/image-demo/src/imgdemo/mainwindow.ui @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>Image Demo</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QGroupBox" name="origin_container"> + <property name="title"> + <string>Origin Image</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="origin_img"> + <property name="text"> + <string>Source</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="result_container"> + <property name="title"> + <string>Filtered Image</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="result_img"> + <property name="text"> + <string>Result</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>Dummy Widget</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>22</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>&File</string> + </property> + <addaction name="actionChoose_Image"/> + <addaction name="actionSave_Image"/> + </widget> + <addaction name="menuFile"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionChoose_Image"> + <property name="icon"> + <iconset theme="QIcon::ThemeIcon::FolderOpen"/> + </property> + <property name="text"> + <string>Choose Image</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionSave_Image"> + <property name="icon"> + <iconset theme="QIcon::ThemeIcon::DocumentSave"/> + </property> + <property name="text"> + <string>Save Image</string> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui> diff --git a/image-demo/src/imgdemo/ui_mainwindow.py b/image-demo/src/imgdemo/ui_mainwindow.py new file mode 100644 index 0000000..6a997bd --- /dev/null +++ b/image-demo/src/imgdemo/ui_mainwindow.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'mainwindow.ui' +## +## Created by: Qt User Interface Compiler version 6.7.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient, + QCursor, QFont, QFontDatabase, QGradient, + QIcon, QImage, QKeySequence, QLinearGradient, + QPainter, QPalette, QPixmap, QRadialGradient, + QTransform) +from PySide6.QtWidgets import (QApplication, QGroupBox, QHBoxLayout, QLabel, + QMainWindow, QMenu, QMenuBar, QPushButton, + QSizePolicy, QStatusBar, QVBoxLayout, QWidget) + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + if not MainWindow.objectName(): + MainWindow.setObjectName(u"MainWindow") + MainWindow.resize(800, 600) + self.actionChoose_Image = QAction(MainWindow) + self.actionChoose_Image.setObjectName(u"actionChoose_Image") + icon = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.FolderOpen)) + self.actionChoose_Image.setIcon(icon) + self.actionSave_Image = QAction(MainWindow) + self.actionSave_Image.setObjectName(u"actionSave_Image") + icon1 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentSave)) + self.actionSave_Image.setIcon(icon1) + self.centralwidget = QWidget(MainWindow) + self.centralwidget.setObjectName(u"centralwidget") + self.verticalLayout_3 = QVBoxLayout(self.centralwidget) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.origin_container = QGroupBox(self.centralwidget) + self.origin_container.setObjectName(u"origin_container") + self.verticalLayout_2 = QVBoxLayout(self.origin_container) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.origin_img = QLabel(self.origin_container) + self.origin_img.setObjectName(u"origin_img") + + self.verticalLayout_2.addWidget(self.origin_img) + + + self.horizontalLayout.addWidget(self.origin_container) + + self.result_container = QGroupBox(self.centralwidget) + self.result_container.setObjectName(u"result_container") + self.verticalLayout = QVBoxLayout(self.result_container) + self.verticalLayout.setObjectName(u"verticalLayout") + self.result_img = QLabel(self.result_container) + self.result_img.setObjectName(u"result_img") + + self.verticalLayout.addWidget(self.result_img) + + + self.horizontalLayout.addWidget(self.result_container) + + + self.verticalLayout_3.addLayout(self.horizontalLayout) + + self.pushButton = QPushButton(self.centralwidget) + self.pushButton.setObjectName(u"pushButton") + + self.verticalLayout_3.addWidget(self.pushButton) + + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QMenuBar(MainWindow) + self.menubar.setObjectName(u"menubar") + self.menubar.setGeometry(QRect(0, 0, 800, 22)) + self.menuFile = QMenu(self.menubar) + self.menuFile.setObjectName(u"menuFile") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QStatusBar(MainWindow) + self.statusbar.setObjectName(u"statusbar") + MainWindow.setStatusBar(self.statusbar) + + self.menubar.addAction(self.menuFile.menuAction()) + self.menuFile.addAction(self.actionChoose_Image) + self.menuFile.addAction(self.actionSave_Image) + + self.retranslateUi(MainWindow) + + QMetaObject.connectSlotsByName(MainWindow) + # setupUi + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Image Demo", None)) + self.actionChoose_Image.setText(QCoreApplication.translate("MainWindow", u"Choose Image", None)) +#if QT_CONFIG(shortcut) + self.actionChoose_Image.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+O", None)) +#endif // QT_CONFIG(shortcut) + self.actionSave_Image.setText(QCoreApplication.translate("MainWindow", u"Save Image", None)) +#if QT_CONFIG(shortcut) + self.actionSave_Image.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+S", None)) +#endif // QT_CONFIG(shortcut) + self.origin_container.setTitle(QCoreApplication.translate("MainWindow", u"Origin Image", None)) + self.origin_img.setText(QCoreApplication.translate("MainWindow", u"Source", None)) + self.result_container.setTitle(QCoreApplication.translate("MainWindow", u"Filtered Image", None)) + self.result_img.setText(QCoreApplication.translate("MainWindow", u"Result", None)) + self.pushButton.setText(QCoreApplication.translate("MainWindow", u"Dummy Widget", None)) + self.menuFile.setTitle(QCoreApplication.translate("MainWindow", u"&File", None)) + # retranslateUi + diff --git a/num-int/src/numint/ui_mainwindow.py b/num-int/src/numint/ui_mainwindow.py deleted file mode 100644 index 84d39bb..0000000 --- a/num-int/src/numint/ui_mainwindow.py +++ /dev/null @@ -1,251 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'mainwindow.ui' -## -## Created by: Qt User Interface Compiler version 6.7.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, - QMetaObject, QObject, QPoint, QRect, - QSize, QTime, QUrl, Qt) -from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, - QFont, QFontDatabase, QGradient, QIcon, - QImage, QKeySequence, QLinearGradient, QPainter, - QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QButtonGroup, QFormLayout, QGroupBox, - QHBoxLayout, QLabel, QLineEdit, QMainWindow, - QMenuBar, QPlainTextEdit, QPushButton, QRadioButton, - QSizePolicy, QSpacerItem, QStatusBar, QVBoxLayout, - QWidget) - -class Ui_MainWindow(object): - def setupUi(self, MainWindow): - if not MainWindow.objectName(): - MainWindow.setObjectName(u"MainWindow") - MainWindow.resize(1411, 889) - self.centralwidget = QWidget(MainWindow) - self.centralwidget.setObjectName(u"centralwidget") - self.horizontalLayout_2 = QHBoxLayout(self.centralwidget) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.verticalLayout = QVBoxLayout() - self.verticalLayout.setObjectName(u"verticalLayout") - self.helpingText = QPlainTextEdit(self.centralwidget) - self.helpingText.setObjectName(u"helpingText") - sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.helpingText.sizePolicy().hasHeightForWidth()) - self.helpingText.setSizePolicy(sizePolicy) - font = QFont() - font.setFamilies([u"Noto Mono"]) - self.helpingText.setFont(font) - self.helpingText.setReadOnly(True) - - self.verticalLayout.addWidget(self.helpingText) - - self.functionInfo = QGroupBox(self.centralwidget) - self.functionInfo.setObjectName(u"functionInfo") - self.formLayout_3 = QFormLayout(self.functionInfo) - self.formLayout_3.setObjectName(u"formLayout_3") - self.label_start = QLabel(self.functionInfo) - self.label_start.setObjectName(u"label_start") - - self.formLayout_3.setWidget(0, QFormLayout.LabelRole, self.label_start) - - self.function = QLineEdit(self.functionInfo) - self.function.setObjectName(u"function") - - self.formLayout_3.setWidget(0, QFormLayout.FieldRole, self.function) - - self.label_fn = QLabel(self.functionInfo) - self.label_fn.setObjectName(u"label_fn") - - self.formLayout_3.setWidget(1, QFormLayout.LabelRole, self.label_fn) - - self.startValue = QLineEdit(self.functionInfo) - self.startValue.setObjectName(u"startValue") - - self.formLayout_3.setWidget(1, QFormLayout.FieldRole, self.startValue) - - self.label_end = QLabel(self.functionInfo) - self.label_end.setObjectName(u"label_end") - - self.formLayout_3.setWidget(2, QFormLayout.LabelRole, self.label_end) - - self.endValue = QLineEdit(self.functionInfo) - self.endValue.setObjectName(u"endValue") - - self.formLayout_3.setWidget(2, QFormLayout.FieldRole, self.endValue) - - - self.verticalLayout.addWidget(self.functionInfo) - - self.breakRule = QGroupBox(self.centralwidget) - self.breakRule.setObjectName(u"breakRule") - self.formLayout_2 = QFormLayout(self.breakRule) - self.formLayout_2.setObjectName(u"formLayout_2") - self.label_4 = QLabel(self.breakRule) - self.label_4.setObjectName(u"label_4") - - self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_4) - - self.espilon = QLineEdit(self.breakRule) - self.espilon.setObjectName(u"espilon") - sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed) - sizePolicy1.setHorizontalStretch(0) - sizePolicy1.setVerticalStretch(0) - sizePolicy1.setHeightForWidth(self.espilon.sizePolicy().hasHeightForWidth()) - self.espilon.setSizePolicy(sizePolicy1) - - self.formLayout_2.setWidget(2, QFormLayout.FieldRole, self.espilon) - - self.label_5 = QLabel(self.breakRule) - self.label_5.setObjectName(u"label_5") - - self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_5) - - self.section = QLineEdit(self.breakRule) - self.section.setObjectName(u"section") - sizePolicy1.setHeightForWidth(self.section.sizePolicy().hasHeightForWidth()) - self.section.setSizePolicy(sizePolicy1) - - self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.section) - - self.breakMethodBox = QGroupBox(self.breakRule) - self.breakMethodBox.setObjectName(u"breakMethodBox") - self.horizontalLayout = QHBoxLayout(self.breakMethodBox) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.minEpsilonMethod = QRadioButton(self.breakMethodBox) - self.breakMethod = QButtonGroup(MainWindow) - self.breakMethod.setObjectName(u"breakMethod") - self.breakMethod.addButton(self.minEpsilonMethod) - self.minEpsilonMethod.setObjectName(u"minEpsilonMethod") - - self.horizontalLayout.addWidget(self.minEpsilonMethod) - - self.numberOfSectionsMethod = QRadioButton(self.breakMethodBox) - self.breakMethod.addButton(self.numberOfSectionsMethod) - self.numberOfSectionsMethod.setObjectName(u"numberOfSectionsMethod") - - self.horizontalLayout.addWidget(self.numberOfSectionsMethod) - - - self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.breakMethodBox) - - - self.verticalLayout.addWidget(self.breakRule) - - self.plotBtn = QPushButton(self.centralwidget) - self.plotBtn.setObjectName(u"plotBtn") - - self.verticalLayout.addWidget(self.plotBtn) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) - - self.verticalLayout.addItem(self.verticalSpacer) - - self.riemannSumGruppe = QGroupBox(self.centralwidget) - self.riemannSumGruppe.setObjectName(u"riemannSumGruppe") - self.formLayout = QFormLayout(self.riemannSumGruppe) - self.formLayout.setObjectName(u"formLayout") - self.label = QLabel(self.riemannSumGruppe) - self.label.setObjectName(u"label") - - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label) - - self.leftSum = QLineEdit(self.riemannSumGruppe) - self.leftSum.setObjectName(u"leftSum") - sizePolicy1.setHeightForWidth(self.leftSum.sizePolicy().hasHeightForWidth()) - self.leftSum.setSizePolicy(sizePolicy1) - self.leftSum.setReadOnly(True) - - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.leftSum) - - self.label_2 = QLabel(self.riemannSumGruppe) - self.label_2.setObjectName(u"label_2") - - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2) - - self.rightSum = QLineEdit(self.riemannSumGruppe) - self.rightSum.setObjectName(u"rightSum") - sizePolicy1.setHeightForWidth(self.rightSum.sizePolicy().hasHeightForWidth()) - self.rightSum.setSizePolicy(sizePolicy1) - self.rightSum.setReadOnly(True) - - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.rightSum) - - self.label_3 = QLabel(self.riemannSumGruppe) - self.label_3.setObjectName(u"label_3") - - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3) - - self.numOfSections = QLineEdit(self.riemannSumGruppe) - self.numOfSections.setObjectName(u"numOfSections") - - self.formLayout.setWidget(2, QFormLayout.FieldRole, self.numOfSections) - - - self.verticalLayout.addWidget(self.riemannSumGruppe) - - - self.horizontalLayout_2.addLayout(self.verticalLayout) - - self.plotBox = QGroupBox(self.centralwidget) - self.plotBox.setObjectName(u"plotBox") - self.plotBox.setEnabled(True) - sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) - sizePolicy2.setHorizontalStretch(0) - sizePolicy2.setVerticalStretch(0) - sizePolicy2.setHeightForWidth(self.plotBox.sizePolicy().hasHeightForWidth()) - self.plotBox.setSizePolicy(sizePolicy2) - - self.horizontalLayout_2.addWidget(self.plotBox) - - MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QMenuBar(MainWindow) - self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 1411, 22)) - MainWindow.setMenuBar(self.menubar) - self.statusbar = QStatusBar(MainWindow) - self.statusbar.setObjectName(u"statusbar") - MainWindow.setStatusBar(self.statusbar) - - self.retranslateUi(MainWindow) - - QMetaObject.connectSlotsByName(MainWindow) - # setupUi - - def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Riemann Sum", None)) - self.helpingText.setPlainText(QCoreApplication.translate("MainWindow", u"Die Funktion f(x) kann eine beliebige Kombination von arithmetischen Operationen und Python mathematische Funktion in Modul math sein. Einige Beispiele sind:\n" -"\n" -"x ** 2 0 4\n" -"x ** 3 0 4\n" -"tan(radians(x)) 0 45\n" -"sin(x)**3 + cos(x)**3 0 2*pi\n" -"", None)) - self.functionInfo.setTitle(QCoreApplication.translate("MainWindow", u"Angabe der Funktion", None)) - self.label_start.setText(QCoreApplication.translate("MainWindow", u"Funktion f(x) = ", None)) - self.function.setText(QCoreApplication.translate("MainWindow", u"x ** 2", None)) - self.label_fn.setText(QCoreApplication.translate("MainWindow", u"start", None)) - self.startValue.setText(QCoreApplication.translate("MainWindow", u"0", None)) - self.label_end.setText(QCoreApplication.translate("MainWindow", u"end", None)) - self.endValue.setText(QCoreApplication.translate("MainWindow", u"4", None)) - self.breakRule.setTitle(QCoreApplication.translate("MainWindow", u"Abbuchkriterium", None)) - self.label_4.setText(QCoreApplication.translate("MainWindow", u"Epsilon", None)) - self.label_5.setText(QCoreApplication.translate("MainWindow", u"Anzahl der Sektionen", None)) - self.section.setText(QCoreApplication.translate("MainWindow", u"8", None)) - self.breakMethodBox.setTitle(QCoreApplication.translate("MainWindow", u"Methoden", None)) - self.minEpsilonMethod.setText(QCoreApplication.translate("MainWindow", u"Minimale Epsilon", None)) - self.numberOfSectionsMethod.setText(QCoreApplication.translate("MainWindow", u"Anzahl der Sektionen", None)) - self.plotBtn.setText(QCoreApplication.translate("MainWindow", u"Ok", None)) - self.riemannSumGruppe.setTitle(QCoreApplication.translate("MainWindow", u"Riemann Summe", None)) - self.label.setText(QCoreApplication.translate("MainWindow", u"linke Summe", None)) - self.label_2.setText(QCoreApplication.translate("MainWindow", u"rechte Summe", None)) - self.label_3.setText(QCoreApplication.translate("MainWindow", u"Anzahl der Iterationen", None)) - self.plotBox.setTitle(QCoreApplication.translate("MainWindow", u"Plot", None)) - # retranslateUi - diff --git a/stundenplan/src/pygraph/graphdemo.py b/stundenplan/src/pygraph/graphdemo.py index 2a6cf7d..d8669be 100644 --- a/stundenplan/src/pygraph/graphdemo.py +++ b/stundenplan/src/pygraph/graphdemo.py @@ -2,6 +2,9 @@ class Graph: + """ + represents an undirected and unweighted Graph + """ def __init__(self): self._adjacent: dict[int, set] = {} self._vertex_attribute: dict[int, dict] = {} @@ -25,7 +28,7 @@ u_neighbor.add(v) pass - def add_edges(self, u: int, adjacent:[int]): + def add_edges(self, u: int, adjacent: list[int]): for v in adjacent: self.add_edge(u, v) pass @@ -44,7 +47,7 @@ """ if vertex not in self._adjacent: raise ValueError(f"Graph does not include vertex {vertex}") - old_attributes = self._vertex_attribute.get(vertex) + old_attributes = self._vertex_attribute[vertex] self._vertex_attribute[vertex] = old_attributes | properties return self pass @@ -75,7 +78,7 @@ def adjacent_of(self, vertex: int): if vertex not in self._adjacent: raise ValueError(f"Graph does not include vertex {vertex}") - return sorted( self._adjacent.get(vertex) ) + return sorted( self._adjacent[vertex] ) def for_each_edges(self, action: Callable[[int, int], Any]): """ @@ -87,21 +90,18 @@ for end in self.adjacent_of(start): (first, second) = (start, end) if (start >= end) else (end, start) if first in visited_edges: - visited_adjacent = visited_edges.get(first) + #visited_adjacent = visited_edges.get(first) + visited_adjacent = visited_edges[first] if second not in visited_adjacent: visited_adjacent.add(second) action(start, end) else: - adjacent = set() + adjacent: set[int] = set() visited_edges[first] = adjacent adjacent.add(second) action(start, end) - def get_lecture_name(self, vertex: int): - pass - def set_lecture_name(self, vertex: int, name: str): - pass def __repr__(self): text = "" diff --git a/stundenplan/src/pygraph/shortestpath.py b/stundenplan/src/pygraph/shortestpath.py index 4426f95..5d3e2af 100644 --- a/stundenplan/src/pygraph/shortestpath.py +++ b/stundenplan/src/pygraph/shortestpath.py @@ -1,9 +1,10 @@ import collections +from typing import Mapping from pygraph.graphdemo import Graph -def bfs(g: Graph, start: int) -> {int:int|None}: +def bfs(g: Graph, start: int) -> Graph: """ :param g: @@ -26,3 +27,53 @@ g.merge_attribute(v, visited) queue.append(v) return tree + + +def bfs_dict(g: Graph, start: int) -> Mapping[int, int|None]: + tree = {start:None} + queue = collections.deque() + VISITED = "visited" + not_visited = {VISITED: False} + visited = {VISITED: True} + g.for_each_vertices(lambda v : g.merge_attribute(v, not_visited)) + queue.append(start) # append() is the enqueue() operation of a Queue + g.merge_attribute(start, visited) + while queue: + u = queue.popleft() # popleft() is the dequeue() operation of a Queue + for v in g.adjacent_of(u): + if not g.get_attribute(v)[VISITED]: + tree[v] = u + g.merge_attribute(v, visited) + queue.append(v) + return tree + pass + + +def find_path(g: Graph, u: int, v: int) -> list[int]: + tree = bfs_dict(g, v) + path = [u] + while (current := path[-1]) != v: + precedent = tree[current] + path.append(precedent) + return path + + +def find_path_gpt(g: Graph, u: int, v: int) -> list[int]: + # Erstelle einen BFS-Baum, beginnend bei Knoten v + bfs_tree = bfs_dict(g, v) + + # Wenn u nicht in bfs_tree ist, gibt es keinen Pfad von u nach v + if u not in bfs_tree: + return [] # Kein Pfad gefunden + + # Den Pfad von u nach v rekonstruieren + path = [] + current = u + while current is not None: + path.append(current) + current = bfs_tree[current] + + # Den Pfad umkehren, da wir rückwärts von u nach v gehen + path.reverse() + + return path \ No newline at end of file diff --git a/stundenplan/tests/pygraph/shortestpath_tests.py b/stundenplan/tests/pygraph/shortestpath_tests.py index 6b9b2de..dc914a1 100644 --- a/stundenplan/tests/pygraph/shortestpath_tests.py +++ b/stundenplan/tests/pygraph/shortestpath_tests.py @@ -1,26 +1,57 @@ import unittest from pygraph.graphdemo import Graph -from pygraph.shortestpath import bfs +from pygraph.shortestpath import bfs, bfs_dict, find_path, find_path_gpt class ShortestPathTestCase(unittest.TestCase): def test_bfs(self): g = Graph() g.add_edges(0, [1, 2]) - g.add_edges(1, [0, 3, 4]) - g.add_edges(2, [0, 4, 6, 7]) - g.add_edges(3, [1]) - g.add_edges(4, [1, 2, 5]) - g.add_edges(5, [4]) - g.add_edges(6, [2]) - g.add_edges(7, [2]) - #print(g) - # self.assertEqual(True, False) # add assertion here - + g.add_edges(1, [3, 4]) + g.add_edges(2, [4, 6, 7]) + g.add_edges(4, [5]) + print(g) + print("#") tree = bfs(g, 0) print(tree) + def test_bfs_dict(self): + g = Graph() + g.add_edges(0, [1, 2]) + g.add_edges(1, [3, 4]) + g.add_edges(2, [4, 6, 7]) + g.add_edges(4, [5]) + print(g) + tree = bfs_dict(g, 6) + print("Tree from Vertex 6") + print(tree) + + def test_find_path(self): + g = Graph() + g.add_edges(0, [1, 2]) + g.add_edges(1, [3, 4]) + g.add_edges(2, [4, 6, 7]) + g.add_edges(4, [5]) + print(g) + (u, v) = (6, 5) + path = find_path(g, 6, 5) + print(f"path from {u} to {v}") + print(path) + + def test_find_path_gpt(self): + g = Graph() + g.add_edges(0, [1, 2]) + g.add_edges(1, [3, 4]) + g.add_edges(2, [4, 6, 7]) + g.add_edges(4, [5]) + print(g) + (u, v) = (6, 5) + path = find_path_gpt(g, 6, 5) + print(f"path from {u} to {v}") + print(path) + + if __name__ == '__main__': unittest.main() -- Gitblit v1.10.0-SNAPSHOT