Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added src/osdag/data/ResourceFiles/images/c_beam.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 modified src/osdag/data/ResourceFiles/images/ss_beam.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 16 additions & 5 deletions src/osdag/design_type/flexural_member/flexure.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
from ...utils.common import is800_2007
from ...utils.common.component import *
from osdag.cad.items.plate import Plate
from PyQt5.QtWidgets import QPushButton
from .plot_bmd_sfd import PlotInputWidget

class Flexure(Member):

Expand Down Expand Up @@ -256,11 +258,11 @@ def input_values(self):
# options_list.append(t3)

#
#t4 = (KEY_SUPPORT, KEY_DISP_SUPPORT, TYPE_NOTE,KEY_DISP_SUPPORT1, True, 'No Validator')
#options_list.append(t4)
t4 = (KEY_SUPPORT, KEY_DISP_SUPPORT, TYPE_NOTE,KEY_DISP_SUPPORT1, True, 'No Validator')
options_list.append(t4)

#t12 = (KEY_IMAGE, None, TYPE_IMAGE, Simply_Supported_img, True, 'No Validator')
#options_list.append(t12)
t12 = (KEY_IMAGE, None, TYPE_IMAGE, Simply_Supported_img, True, 'No Validator')
options_list.append(t12)


# t3 = (KEY_BUCKLING_METHOD, KEY_WEB_BUCKLING, TYPE_COMBOBOX, KEY_WEB_BUCKLING_option, False, 'No Validator')
Expand All @@ -286,10 +288,20 @@ def input_values(self):

t8 = (KEY_MOMENT, KEY_DISP_MOMENT, TYPE_TEXTBOX, None, True, 'No Validator')
options_list.append(t8)
bm_button = QPushButton("Plot BMD")
self.bmd_widget = PlotInputWidget("BM")
bm_button.clicked.connect(self.bmd_widget.show)
t8b = ("bm_plot_button", "", 'BUTTON', bm_button, True, "")
options_list.append(t8b)

t8 = (KEY_SHEAR, KEY_DISP_SHEAR, TYPE_TEXTBOX, None, True, 'No Validator')
options_list.append(t8)

sf_button = QPushButton("Plot SFD")
self.sfd_widget = PlotInputWidget("SFD")
sf_button.clicked.connect(self.sfd_widget.show)
t9b = ("sf_plot_button", "", 'BUTTON', sf_button, True, "")
options_list.append(t9b)


return options_list
Expand Down Expand Up @@ -3089,4 +3101,3 @@ def save_design(self, popup_summary):
fname_no_ext = popup_summary['filename']
CreateLatex.save_latex(CreateLatex(), self.report_input, self.report_check, popup_summary, fname_no_ext,
rel_path, Disp_2d_image, Disp_3D_image, module=self.module) #

22 changes: 18 additions & 4 deletions src/osdag/design_type/flexural_member/flexure_cantilever.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
from ...utils.common.Section_Properties_Calculator import BBAngle_Properties
from ...utils.common import is800_2007
from ...utils.common.component import *
from PyQt5.QtWidgets import QPushButton
from .plot_bmd_sfd import PlotInputWidget

# TODO DEBUG
class Flexure_Cantilever(Member):
Expand Down Expand Up @@ -256,11 +258,11 @@ def input_values(self):
# options_list.append(t3)
#
#
#t4 = (KEY_SUPPORT, KEY_DISP_SUPPORT, TYPE_NOTE,KEY_DISP_SUPPORT2, True, 'No Validator')
#options_list.append(t4)
t4 = (KEY_SUPPORT, KEY_DISP_SUPPORT, TYPE_NOTE,KEY_DISP_SUPPORT2, True, 'No Validator')
options_list.append(t4)

#t12 = (KEY_IMAGE, None, TYPE_IMAGE, Cantilever_img, True, 'No Validator')
#options_list.append(t12)
t12 = (KEY_IMAGE, None, TYPE_IMAGE, Cantilever_img, True, 'No Validator')
options_list.append(t12)
#
# t10 = (KEY_TORSIONAL_RES, DISP_TORSIONAL_RES, TYPE_COMBOBOX, Torsion_Restraint_list, True, 'No Validator')
# options_list.append(t10)
Expand All @@ -282,11 +284,23 @@ def input_values(self):

t8 = (KEY_MOMENT, KEY_DISP_MOMENT, TYPE_TEXTBOX, None, True, 'No Validator')
options_list.append(t8)
bm_button = QPushButton("Plot BMD")
self.bmd_widget = PlotInputWidget("BM")
bm_button.clicked.connect(self.bmd_widget.show)
t8b = ("bm_plot_button", "", 'BUTTON', bm_button, True, "")
options_list.append(t8b)

t8 = (KEY_SHEAR, KEY_DISP_SHEAR, TYPE_TEXTBOX, None, True, 'No Validator')
options_list.append(t8)


sf_button = QPushButton("Plot SFD")
self.sfd_widget = PlotInputWidget("SFD")
sf_button.clicked.connect(self.sfd_widget.show)
t9b = ("sf_plot_button", "", 'BUTTON', sf_button, True, "")
options_list.append(t9b)



return options_list

Expand Down
4 changes: 4 additions & 0 deletions src/osdag/design_type/flexural_member/flexure_othersupp.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ def input_values(self):
t8 = (KEY_SHEAR, KEY_DISP_SHEAR, TYPE_TEXTBOX, None, True, 'No Validator')
options_list.append(t8)

t_support = (KEY_SUPPORT, "Support Type", TYPE_COMBOBOX, ["Simply Supported", "Cantilever"], True, "")
options_list.append(t_support)




return options_list
Expand Down
188 changes: 188 additions & 0 deletions src/osdag/design_type/flexural_member/plot_bmd_sfd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QDialog

from PyQt5.QtWidgets import (
QWidget, QLabel, QPushButton, QVBoxLayout, QTableWidget, QTableWidgetItem,
QHBoxLayout, QFileDialog, QHeaderView, QMessageBox
)
import matplotlib.pyplot as plt


class PlotInputWidget(QWidget):
def __init__(self, plot_type="BM"): # "BM" or "SF"
super().__init__()

self.plot_type = plot_type
self.setWindowTitle(f"{'BMD' if plot_type == 'BM' else 'SFD'} Plotter")

self.layout = QVBoxLayout(self)

# Setup Table
self.table = QTableWidget(5, 2)
self.table.setHorizontalHeaderLabels(["Distance (m)", "BM (kNm)" if plot_type == "BM" else "SF (kN)"])
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

self.layout.addWidget(QLabel(f"Enter Distance and {'Bending Moment' if plot_type == 'BM' else 'Shear Force'} values:"))
self.layout.addWidget(self.table)

# Buttons
btn_layout = QHBoxLayout()
self.plot_btn = QPushButton(f"Plot {'BMD' if plot_type == 'BM' else 'SFD'}")
# self.save_btn = QPushButton("Save as PNG")
self.add_row_btn = QPushButton("Add Row")
btn_layout.addWidget(self.add_row_btn)
btn_layout.addWidget(self.plot_btn)
# btn_layout.addWidget(self.save_btn)
self.layout.addLayout(btn_layout)

# Connections
self.add_row_btn.clicked.connect(self.add_row)
self.plot_btn.clicked.connect(self.plot_graph)
# self.save_btn.clicked.connect(self.save_plot)

def add_row(self):
self.table.insertRow(self.table.rowCount())

def get_data(self):
x_vals = []
y_vals = []

for row in range(self.table.rowCount()):
try:
xi = float(self.table.item(row, 0).text())
yi = float(self.table.item(row, 1).text())
x_vals.append(xi)
y_vals.append(yi)
except (ValueError, AttributeError):
continue

if len(x_vals) < 2:
QMessageBox.warning(self, "Invalid Input", "Please enter at least two valid data points.")
return None, None

# Sort by distance
return zip(*sorted(zip(x_vals, y_vals)))

def plot_graph(self):
x, y = self.get_data()
if x is None:
return

color = 'r' if self.plot_type == "BM" else 'b'
title = "Bending Moment Diagram" if self.plot_type == "BM" else "Shear Force Diagram"
ylabel = "BM (kNm)" if self.plot_type == "BM" else "SF (kN)"
# plt.rcParams['home'] = 'none'
fig, ax = plt.subplots(figsize=(8, 4))
line, = ax.plot(x, y, color=color, linewidth=2, marker='o', label=title)

# Draw vertical dashed lines from each point to X-axis
for xi, yi in zip(x, y):
ax.vlines(xi, 0, yi, colors=color, linestyles='dashed', alpha=0.6)

ax.set_title(title)
ax.set_xlabel("Distance (m)")
ax.set_ylabel(ylabel)
ax.grid(True)
ax.axhline(0, color='black', linewidth=1)

# Hover annotation
annot = ax.annotate("", xy=(0,0), xytext=(15,15), textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(ind):
index = ind["ind"][0]
x_val = x[index]
y_val = y[index]
annot.xy = (x_val, y_val)
annot.set_text(f"x={x_val:.2f}\ny={y_val:.2f}")
annot.get_bbox_patch().set_alpha(0.9)

def hover(event):
if event.inaxes == ax and event.xdata is not None:
x_mouse = event.xdata

# Find two x-values around the mouse (for interpolation)
for i in range(len(x) - 1):
if x[i] <= x_mouse <= x[i + 1]:
# Linear interpolation
x1, x2 = x[i], x[i + 1]
y1, y2 = y[i], y[i + 1]

# Interpolated y value
slope = (y2 - y1) / (x2 - x1)
y_interp = y1 + slope * (x_mouse - x1)

# Update annotation
annot.xy = (x_mouse, y_interp)
annot.set_text(f"x={x_mouse:.2f}\ny={y_interp:.2f}")
annot.set_visible(True)
fig.canvas.draw_idle()
return

annot.set_visible(False)
fig.canvas.draw_idle()


fig.canvas.mpl_connect("motion_notify_event", hover)
plt.tight_layout()
plt.legend()
plt.show()


def save_plot(self):
x, y = self.get_data()
if x is None:
return

fname, _ = QFileDialog.getSaveFileName(self, "Save Plot", "", "PNG Files (*.png)")
if fname:
color = 'r' if self.plot_type == "BM" else 'b'
title = "Bending Moment Diagram" if self.plot_type == "BM" else "Shear Force Diagram"
ylabel = "BM (kNm)" if self.plot_type == "BM" else "SF (kN)"

plt.figure(figsize=(8, 4))
plt.plot(x, y, color=color, linewidth=2, marker='o')
for xi, yi in zip(x, y):
plt.vlines(xi, 0, yi, colors=color, linestyles='dashed', alpha=0.7)
plt.axhline(0, color='black', linewidth=1)
plt.title(title)
plt.xlabel("Distance (m)")
plt.ylabel(ylabel)
plt.grid(True)
plt.tight_layout()
plt.savefig(fname)
plt.close()

def keyPressEvent(self, event):
if event.matches(QKeySequence.Paste):
clipboard = QApplication.clipboard()
text = clipboard.text()
rows = text.strip().split("\n")
current_row = self.table.currentRow()
current_col = self.table.currentColumn()

for r_idx, row_data in enumerate(rows):
columns = row_data.split("\t")
for c_idx, cell in enumerate(columns):
target_row = current_row + r_idx
target_col = current_col + c_idx
# Expand if necessary
if target_row >= self.table.rowCount():
self.table.insertRow(self.table.rowCount())
item = QTableWidgetItem(cell.strip())
self.table.setItem(target_row, target_col, item)
else:
super().keyPressEvent(event)
def showEvent(self, event):
# Clear table contents every time the widget is shown
self.table.clearContents()
self.table.setRowCount(5) # Reset to default number of rows
super().showEvent(event)



2 changes: 1 addition & 1 deletion src/osdag/gui/ui_OsdagMainPage.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def setupUi(self, MainWindow):
self.comboBox_help.setCurrentIndex(0)
self.myStackedWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Osdag"))
Expand Down
30 changes: 28 additions & 2 deletions src/osdag/gui/ui_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pandas as pd
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from .ui_tutorial import Ui_Tutorial
from .ui_aboutosdag import Ui_AboutOsdag
Expand Down Expand Up @@ -60,7 +60,10 @@
from ..get_DPI_scale import scale,height,width
from ..cad.cad3dconnection import cadconnection
from pynput.mouse import Button, Controller

from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import QThread
from PyQt5.QtCore import pyqtSignal, QObject, QEvent
from PyQt5.QtCore import *
class MyTutorials(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
Expand Down Expand Up @@ -582,6 +585,11 @@ def setupUi(self, MainWindow, main,folder):
for option in option_list:
lable = option[1]
type = option[2]
if type == 'BUTTON':
b = option[3]
b.setObjectName(option[0])
in_layout2.addWidget(b, j, 2, 1, 1)

if type not in [TYPE_TITLE, TYPE_IMAGE, TYPE_MODULE, TYPE_IMAGE_COMPRESSION]:
l = QtWidgets.QLabel(self.dockWidgetContents)
l.setObjectName(option[0] + "_label")
Expand Down Expand Up @@ -865,6 +873,7 @@ def setupUi(self, MainWindow, main,folder):
else:
for t in updated_list:
for key_name in t[0]:

key_changed = self.dockWidgetContents.findChild(QtWidgets.QWidget, key_name)
self.on_change_connect(key_changed, updated_list, data, main)
print(f"key_name{key_name} \n key_changed{key_changed} \n self.on_change_connect ")
Expand Down Expand Up @@ -2133,7 +2142,24 @@ def common_function_for_save_and_design(self, main, data, trigger_type):
action.setEnabled(True)
fName = str('./ResourceFiles/images/3d.png')
file_extension = fName.split(".")[-1]

# if file_extension == 'png':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment: add reason or delete commented code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented code was there in the source code, due to line change i think it is being reflected

# self.display.ExportToImage(fName)
# im = Image.open('./ResourceFiles/images/3d.png')
# w,h=im.size
# if(w< 640 or h < 360):
# print('Re-taking Screenshot')
# self.resize(700,500)
# self.outputDock.hide()
# self.inputDock.hide()
# self.textEdit.hide()
# QTimer.singleShot(0, lambda:self.retakeScreenshot(fName))

else:
for fName in ['3d.png', 'top.png',
'front.png', 'side.png']:
with open("./ResourceFiles/images/"+fName, 'w'):
pass
self.display.EraseAll()
for chkbox in main.get_3d_components(main):
self.frame.findChild(QtWidgets.QCheckBox, chkbox[0]).setEnabled(False)
Expand Down