Skip to content

Commit

Permalink
Fixed major bug with R constraint in GUI, added internal screenshot f…
Browse files Browse the repository at this point in the history
…eature, added doc pictures
  • Loading branch information
mlauer154 committed Sep 26, 2023
1 parent fc12358 commit e9e734e
Show file tree
Hide file tree
Showing 21 changed files with 380 additions and 37 deletions.
11 changes: 8 additions & 3 deletions docs/source/gui.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
GUI help documentation test:
GUI Help
========

.. raw::html
:file: gui_help/test.html
This section contains tutorials and helpful hints for the pymead GUI.

.. toctree::

gui_help/gui_airfoil.rst
gui_help/gui_opt.rst
112 changes: 112 additions & 0 deletions docs/source/gui_help/gui_airfoil.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
Airfoil Generation
==================

The following steps show how to create and save an airfoil from the pymead GUI.

Next, we will insert some ``FreePoint``\ s into the airfoil, which adds additional degrees
of freedom to individual Bézier curves. To insert a ``FreePoint`` from the GUI, right-click
on the desired airfoil in the Parameter Tree, which brings up a context menu as shown below:

.. image:: ../images/fp_ap_menu_dark.png
:align: center
:class: only-dark

.. image:: ../images/fp_ap_menu_light.png
:align: center
:class: only-light

This brings up a dialog as shown below.

.. image:: ../images/fp_menu_dark.png
:align: center
:class: only-dark

.. image:: ../images/fp_menu_light.png
:align: center
:class: only-light

Here is a description of each of the ``FreePoint`` menu items:

.. list-table::
:widths: 20 80
:header-rows: 1

* - Item
- Parameter
* - x
- Distance from the origin in the "Geometry" window along the x-axis
* - y
- Distance from the origin in the "Geometry" window along the y-axis
* - Previous Anchor Point
- Parent ``AnchorPoint`` to which this ``FreePoint`` belongs. More specifically, the ``FreePoint``
will be inserted into the Bézier curve which has this ``AnchorPoint`` as its first ``ControlPoint``
using counter-clockwise ordering. For an airfoil with no custom ``AnchorPoint``\ s, inserting this
``FreePoint`` with the Previous Anchor Point set to ``"te_1"`` corresponds to adding a control
point to the airfoil's upper surface, while inserting a ``FreePoint`` with the
Previous Anchor Point set to ``"le"`` corresponds to adding a control point to the airfoil's
lower surface. Note that ``"te_1"`` represents the upper trailing edge point,
which is distinct from the lower trailing edge point in the case of an airfoil with a blunt
trailing edge.
* - Previous Free Point
- Similar to the "Previous Anchor Point" item, this item sets the ``FreePoint`` insertion index
within the Bézier curve's control point matrix using counter-clockwise ordering. The
difference here is that an existing ``FreePoint`` is specified, rather than an ``AnchorPoint``.
Note that if no ``FreePoint``\ s have been added yet to the Bézier curve corresponding to the
``AnchorPoint`` specified by "Previous Anchor Point", ``None`` is automatically selected.

.. image:: ../images/ap_menu_dark.png
:align: center
:class: only-dark

.. image:: ../images/ap_menu_light.png
:align: center
:class: only-light

Here is a description of each of the ``AnchorPoint`` menu items:

.. list-table::
:widths: 20 80
:header-rows: 1

* - Item
- Parameter
* - x
- Distance from the origin in the "Geometry" window along the x-axis
* - y
- Distance from the origin in the "Geometry" window along the y-axis
* - L
- Distance between the control points located immediately before and after the ``AnchorPoint``
in the counter-clockwise ordering divided by the chord length of the airfoil.
* - R
- Radius of curvature of the airfoil at the ``AnchorPoint`` divided by the chord length of the
airfoil.
* - r
- Ratio of the distance between the control point immediately upstream of the ``AnchorPoint`` and
the ``AnchorPoint`` itself to the distance between the control points located immediately before
and after the ``AnchorPoint``\ . Here, "upstream" means after the ``AnchorPoint`` in the
counter-clockwise ordering for an ``AnchorPoint`` on the upper surface and before the
``AnchorPoint`` for an ``AnchorPoint`` on the lower surface. This is normally in the
range :math:`[0,1]`; however, this is not enforced.
* - phi
- "Tilt" of the line connecting the control points immediately before and after the ``AnchorPoint``.
Regardless of whether the ``AnchorPoint`` is located on the airfoil upper surface or lower surface,
positive values of "phi" tilt the line toward the leading edge, while negative values of "phi"
tilt the line away from the leading edge.
* - psi1
-
* - Previous Anchor Point
- Parent ``AnchorPoint`` to which this ``FreePoint`` belongs. More specifically, the ``FreePoint``
will be inserted into the Bézier curve which has this ``AnchorPoint`` as its first ``ControlPoint``
using counter-clockwise ordering. For an airfoil with no custom ``AnchorPoint``\ s, inserting this
``FreePoint`` with the Previous Anchor Point set to ``"te_1"`` corresponds to adding a control
point to the airfoil's upper surface, while inserting a ``FreePoint`` with the
Previous Anchor Point set to ``"le"`` corresponds to adding a control point to the airfoil's
lower surface. Note that ``"te_1"`` represents the upper trailing edge point,
which is distinct from the lower trailing edge point in the case of an airfoil with a blunt
trailing edge.
* - Previous Free Point
- Similar to the "Previous Anchor Point" item, this item sets the ``FreePoint`` insertion index
within the Bézier curve's control point matrix using counter-clockwise ordering. The
difference here is that an existing ``FreePoint`` is specified, rather than an ``AnchorPoint``.
Note that if no ``FreePoint``\ s have been added yet to the Bézier curve corresponding to the
``AnchorPoint`` specified by "Previous Anchor Point", ``None`` is automatically selected.
2 changes: 2 additions & 0 deletions docs/source/gui_help/gui_opt.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Optimization
============
Binary file added docs/source/images/ap_menu_dark.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/ap_menu_light.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/fp_ap_menu_dark.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/fp_ap_menu_light.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/fp_menu_dark.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/fp_menu_light.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@ Contents
--------

.. toctree::
:maxdepth: 5

install
quick_start

.. toctree::
:maxdepth: 2

tutorials
api
gui

.. toctree::
:maxdepth: 3

api
7 changes: 4 additions & 3 deletions docs/source/quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ containing the ``gui.py`` file (the ``gui`` module) and then run the script usin
Alternatively, users working in an IDE can navigate to the ``gui`` module by clicking through the directory tree.

GUI documentation:
..
GUI documentation:
.. raw:: html
:file: gui_help/test.html
.. raw:: html
:file: gui_help/test.html

Programmatic Interface
======================
29 changes: 21 additions & 8 deletions pymead/core/anchor_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ def map_psi_to_airfoil_csys_inverse():
if self.anchor_type == 'upper_surf':
if self.R.value > 0:
# angle = np.pi + psi + phi
self.psi1.value = self.abs_psi1 - np.pi - self.phi.value
self.psi1.value = self.abs_psi1 + np.pi - self.phi.value
else:
# angle = np.pi - psi + phi
self.psi1.value = -self.abs_psi1 + np.pi + self.phi.value
Expand Down Expand Up @@ -533,7 +533,7 @@ def map_psi_to_airfoil_csys_inverse():
self.psi1.value = np.pi - self.abs_psi1 - self.phi.value
else:
# angle = np.pi + psi - phi
self.psi1.value = self.abs_psi1 - np.pi + self.phi.value
self.psi1.value = self.abs_psi1 + np.pi + self.phi.value
elif self.anchor_type == 'le':
if self.R.value > 0:
# angle = -psi + phi
Expand All @@ -546,27 +546,40 @@ def map_psi_to_airfoil_csys_inverse():

map_psi_to_airfoil_csys_inverse()

# Take care of the case where R is bounded and the mouse is dragged such that R would flip signs otherwise
if self.R.at_boundary:
for psi in [self.psi1, self.psi2]:
if self.anchor_type == "le":
if psi.value > np.pi / 2:
psi.value -= 2 * (psi.value - np.pi / 2)
elif psi.value < -np.pi / 2:
psi.value += 2 * (psi.value - np.pi / 2)
else:
if psi.value > np.pi:
psi.value -= 2 * (psi.value - np.pi)
elif psi.value < 0.0:
psi.value *= -1

if (minus_plus == 'minus' and self.anchor_type in ['upper_surf', 'le']) or (
minus_plus == 'plus' and self.anchor_type == 'lower_surf'):
apsi = self.psi1.value
else:
apsi = self.psi2.value

if self.R.active and not self.R.linked:
R_multiplier = -1.0 if negate_R else 1.0
if self.tag == 'le':
if minus_plus == 'minus':
self.R.value = self.Lt_minus ** 2 / (
self.R.value = R_multiplier * self.Lt_minus ** 2 / (
self.Lc_minus * (1 - 1 / self.n1) * np.sin(apsi + np.pi / 2))
else:
self.R.value = self.Lt_plus ** 2 / (
self.R.value = R_multiplier * self.Lt_plus ** 2 / (
self.Lc_plus * (1 - 1 / self.n2) * np.sin(apsi + np.pi / 2))
else:
if minus_plus == 'minus':
self.R.value = self.Lt_minus ** 2 / (self.Lc_minus * (1 - 1 / self.n1) * np.sin(apsi))
self.R.value = R_multiplier * self.Lt_minus ** 2 / (self.Lc_minus * (1 - 1 / self.n1) * np.sin(apsi))
else:
self.R.value = self.Lt_plus ** 2 / (self.Lc_plus * (1 - 1 / self.n2) * np.sin(apsi))
if negate_R:
self.R.value *= -1
self.R.value = R_multiplier * self.Lt_plus ** 2 / (self.Lc_plus * (1 - 1 / self.n2) * np.sin(apsi))

def recalculate_ap_branch_props_from_g1_pt(self, minus_plus: str, measured_phi, measured_Lt):
"""
Expand Down
4 changes: 1 addition & 3 deletions pymead/core/param.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ def __init__(self, value: float or typing.Tuple[float], bounds: tuple = (-np.inf
active: bool or typing.Tuple[bool] = True, linked: bool or typing.Tuple[bool] = False,
func_str: str = None, name: str = None, periodic: bool = False):
"""
### Description:
This is the class used to define parameters used for the airfoil and airfoil parametrization definitions
in `pymead`.
in pymead.
### Args:
Expand Down
7 changes: 0 additions & 7 deletions pymead/gui/dialog_layouts.py

This file was deleted.

34 changes: 34 additions & 0 deletions pymead/gui/dialog_widgets/screenshot_dialog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"window": {
"label": {
"w": "QLabel",
"text": "Select window",
"grid": [0, 0, 1, 1],
"tool_tip": "Name of the window to screenshot"
},
"combobox": {
"w": "QComboBox",
"addItems": ["Full Window","Parameter Tree", "Geometry", "Analysis", "Console"],
"grid": [0, 1, 1, 2]
}
},
"choose_image_file": {
"label": {
"w": "QLabel",
"text": "Choose image file",
"grid": [1, 0, 1, 1],
"tool_tip": "Choose a name for the image file (JPEG format)"
},
"line": {
"w": "QLineEdit",
"text": "",
"grid": [1, 1, 1, 1]
},
"button": {
"w": "QPushButton",
"text": "Select",
"grid": [1, 2, 1, 1],
"func": "select_jpg_file"
}
}
}
7 changes: 7 additions & 0 deletions pymead/gui/file_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ def select_json_file(parent, line_edit: QLineEdit = None):
return single_file_output_rule(file_dialog, line_edit)


def select_jpg_file(parent, line_edit: QLineEdit = None):
file_dialog = QFileDialog(parent)
file_dialog.setFileMode(QFileDialog.AnyFile)
file_dialog.setNameFilter(parent.tr("JPEG Files (*.jpg *.jpeg)"))
return single_file_output_rule(file_dialog, line_edit)


def select_existing_json_file(parent, line_edit: QLineEdit = None):
file_dialog = QFileDialog(parent)
file_dialog.setFileMode(QFileDialog.ExistingFile)
Expand Down
44 changes: 43 additions & 1 deletion pymead/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from pymead.gui.input_dialog import LoadDialog, SaveAsDialog, OptimizationSetupDialog, \
MultiAirfoilDialog, ColorInputDialog, ExportCoordinatesDialog, ExportControlPointsDialog, AirfoilPlotDialog, \
AirfoilMatchingDialog, MSESFieldPlotDialog, ExportIGESDialog, XFOILDialog, NewMEADialog, EditBoundsDialog, \
ExitDialog
ExitDialog, ScreenshotDialog
from pymead.gui.pymeadPColorMeshItem import PymeadPColorMeshItem
from pymead.gui.analysis_graph import AnalysisGraph
from pymead.gui.parameter_tree import MEAParamTree
Expand Down Expand Up @@ -350,6 +350,48 @@ def recursively_add_menus(menu: dict, menu_bar: QObject):

recursively_add_menus(menu_data, self.menu_bar)

def take_screenshot(self):

if hasattr(self.dockable_tab_window, "current_dock_widget"):
analysis_id = self.dockable_tab_window.current_dock_widget.winId()
else:
analysis_id = self.dockable_tab_window.dock_widgets[-1].winId()

id_dict = {
"Full Window": self.winId(),
"Parameter Tree": self.param_tree_instance.t.winId(),
"Geometry": self.dockable_tab_window.dock_widgets[0].winId(),
"Analysis": analysis_id,
"Console": self.text_area.winId()
}

dialog = ScreenshotDialog(self)
if dialog.exec_():
inputs = dialog.getInputs()

# Take the screenshot
screen = QApplication.primaryScreen()
screenshot = screen.grabWindow(id_dict[inputs["window"]])

# Handle improper directory names and file extensions
file_path_split = os.path.split(inputs['image_file'])
dir_name = file_path_split[0]
file_name = file_path_split[1]
file_name_no_ext = os.path.splitext(file_name)[0]
file_ext = os.path.splitext(file_name)[1]
if file_ext not in [".jpg", ".jpeg"]:
file_ext = ".jpg"

final_file_name = os.path.join(dir_name, file_name_no_ext + file_ext)

if os.path.isdir(dir_name):
screenshot.save(final_file_name, "jpg") # Save the screenshot
self.disp_message_box(f"{inputs['window']} window screenshot saved to {final_file_name}",
message_mode="info")
else:
self.disp_message_box(f"Directory {dir_name} for"
f"file {file_name} not found")

def save_as_mea(self):
dialog = SaveAsDialog(self)
if dialog.exec_():
Expand Down
3 changes: 2 additions & 1 deletion pymead/gui/gui_settings/menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"Tools": {
"Plot Airfoil from AirfoilTools": "plot_airfoil_from_airfoiltools",
"Match Airfoil": "match_airfoil",
"Airfoil Statistics": "display_airfoil_statistics"
"Airfoil Statistics": "display_airfoil_statistics",
"Take Screenshot": ["take_screenshot", "Ctrl+Shift+S"]
},
"Plot": {
"Geometry From File": "plot_geometry"
Expand Down
Loading

0 comments on commit e9e734e

Please sign in to comment.