├── .circleci
└── config.yml
├── .gitignore
├── Init.py
├── InitGui.py
├── LICENSE
├── OSAFEGui.py
├── README.md
├── check_legal.py
├── civilwelcome.py
├── compile.py
├── dxfColorMap.py
├── dxfImportObjects.py
├── dxfLibrary.py
├── dxfReader.py
├── help
├── cover.tex
├── export.tex
├── faq.tex
├── figures
│ ├── assign.png
│ ├── autoload.png
│ ├── civil.png
│ ├── columnedit.png
│ ├── comboview.png
│ ├── dataview.png
│ ├── excel.png
│ ├── excel2.png
│ ├── export.png
│ ├── geometry.png
│ ├── geometry2.png
│ ├── import_model_from_etabs.png
│ ├── logo.svg
│ ├── make_auto_strip.png
│ └── punch.png
├── freecad.tex
├── help.pdf
├── help.tex
├── import_model.html
├── import_model.md
├── introduction.tex
├── make_auto_strip.html
├── make_auto_strip.md
├── modify.tex
├── punch_report.cls
├── safe.tex
└── update.tex
├── old_punch
├── Help.pdf
├── axis.py
├── foundraw
│ ├── geom.py
│ ├── pyconcreteWelcome.py
│ └── safe.py
├── geom.py
├── safe.py
└── test_safe.py
├── osafe_draw
├── draw_base_foundation.py
├── draw_beam.py
├── draw_rectangular_slab.py
├── draw_slab.py
└── draw_strip.py
├── osafe_funcs
└── osafe_funcs.py
├── osafe_gui
└── gui_automatic_rebars.py
├── osafe_images
├── auto_strip.svg
├── automatic_base_foundation.svg
├── banner.jpg
├── base_foundation.svg
├── base_plate.svg
├── beam.svg
├── cancel.png
├── change_branch.svg
├── civil-engineering.png
├── civil_Welcome.svg
├── civiltools.png
├── copy.svg
├── draw_strip.svg
├── dxf.svg
├── etabs.png
├── explode.svg
├── explode_foundation.svg
├── export.svg
├── export_strips.svg
├── f2k.svg
├── force.svg
├── foundation.svg
├── help.png
├── import.svg
├── import_dxf.svg
├── opening.svg
├── osafe_rebar.svg
├── pdf.svg
├── png.png
├── preferences-OSAFE.svg
├── preferences-punch.svg
├── punch.svg
├── rectangle.svg
├── rectangular_slab.svg
├── refresh.svg
├── run.svg
├── safe.png
├── segment.png
├── slab.svg
├── strip.svg
├── tick.svg
├── trapozeidal.svg
├── update.png
├── update.svg
├── view_arch_wall.svg
├── view_base_foundation.svg
├── view_beams.svg
├── view_columns.svg
├── view_design_layer.svg
├── view_design_layer_a.svg
├── view_design_layer_b.svg
├── view_foundations.svg
├── view_osafe_rebar.svg
├── view_punch.svg
├── view_slabs.svg
├── wall.svg
├── wireframe.svg
├── word.png
└── xlsx.png
├── osafe_import_export
├── export.py
├── report.py
├── safe_read_write_f2k.py
└── templates
│ └── punch_default.docx
├── osafe_objects
├── base_foundation.py
├── base_plate.py
├── beam.py
├── colorbar.py
├── etabs_foundation.py
├── f2k_object.py
├── foundation.py
├── opening.py
├── osafe_rebar.py
├── punch.py
├── rectangular_slab.py
├── slab.py
├── strip.py
└── trapezoidal_slab.py
├── osafe_py_widgets
├── base_foundation_panel.py
├── change_branch.py
├── create_f2k_command.py
├── draw_automatic_rebars.py
├── draw_automatic_strip.py
├── etabs_panel.py
├── etabs_punch.py
├── explode_foundation.py
├── explode_seismic_load_patterns.py
├── export
│ ├── export_strips_panel.py
│ ├── export_to_dxf_dialog.py
│ └── import_from_dxf_dialog.py
├── force_panel.py
├── foundation_panel.py
├── gui_automatic_strip.py
├── gui_dxf.py
├── gui_export_strips.py
├── gui_punch.py
├── osafe_views.py
├── resource.qrc
├── resource_rc.py
├── safe_panel.py
└── wall_panel.py
├── osafe_statusbar.py
├── osafe_translate_utils.py
├── osafe_widgets
├── base_foundation.ui
├── base_foundation_panel.ui
├── base_plate.ui
├── change_branch.ui
├── civil_welcome.ui
├── column.ui
├── create_f2k.ui
├── draw_automatic_rebars.ui
├── draw_automatic_strip.ui
├── draw_strip.ui
├── edit_objects
│ ├── edit_base_foundation.ui
│ └── edit_osafe_rebars.ui
├── etabs_panel.ui
├── explode_seismic_load_patterns.ui
├── export
│ └── export_to_dxf.ui
├── export_strips_panel.ui
├── force_panel.ui
├── foundation_panel.ui
├── import_from_dxf.ui
├── preferences-OSAFE_visual.ui
├── safe_panel.ui
├── serial.ui
└── wall_panel.ui
├── package.xml
├── requirements.txt
└── test
├── osafe_import_export
├── test_report.py
└── test_safe_read_write_f2k.py
├── osafe_objects
├── test_base_plate.py
├── test_osafe_rebar.py
└── test_strip.py
├── test_beam.py
├── test_etabs_foundation.py
├── test_etabs_punch.py
├── test_f2k_object.py
├── test_files
├── .~lock.davoodabadi_dynamic.xlsx#
├── davoodabadi_dynamic.xlsx
├── freecad
│ ├── adampira.FCStd
│ ├── base_foundation.FCStd
│ ├── base_plate.FCStd
│ ├── circle_column.FCStd
│ ├── kazemi.FCStd
│ ├── khalaji.F2k
│ ├── khalaji.FCStd
│ ├── mat.FCStd
│ ├── rashidzadeh.FCStd
│ ├── strip.FCStd
│ ├── strip_foundation.FCStd
│ ├── test.FCStd
│ └── test_p.FCStd
├── khojasteh_97-07-18.xlsx
├── safdari.xlsx
└── sattari_safe.xlsx
├── test_geom.py
├── test_opening.py
├── test_osafe_funcs.py
├── test_punch.py
├── test_rectangular_slab.py
└── test_trapezoidal_slab.py
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Python CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-python/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers`
11 | - image: circleci/python:3.6.1
12 |
13 | # Specify service dependencies here if necessary
14 | # CircleCI maintains a library of pre-built images
15 | # documented at https://circleci.com/docs/2.0/circleci-images/
16 | # - image: circleci/postgres:9.4
17 |
18 | working_directory: ~/repo
19 |
20 | steps:
21 | - checkout
22 |
23 | # Download and cache dependencies
24 | - restore_cache:
25 | keys:
26 | - v1-dependencies-{{ checksum "requirements.txt" }}
27 | # fallback to using the latest cache if no exact match is found
28 | - v1-dependencies-
29 |
30 | - run:
31 | name: install dependencies
32 | command: |
33 | python3 -m venv venv
34 | . venv/bin/activate
35 | pip install -r requirements.txt
36 |
37 | - save_cache:
38 | paths:
39 | - ./venv
40 | key: v1-dependencies-{{ checksum "requirements.txt" }}
41 |
42 | # run tests!
43 | # this example uses Django's built-in test-runner
44 | # other common Python testing frameworks include pytest and nose
45 | # https://pytest.org
46 | # https://nose.readthedocs.io
47 | - run:
48 | name: run tests
49 | command: |
50 | . venv/bin/activate
51 | python3 -m unittest
52 |
53 | # - store_artifacts:
54 | # path: test-reports
55 | # destination: test-reports
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # pip requirements
39 | requirements.in
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | .hypothesis/
51 | .pytest_cache/
52 |
53 | # Translations
54 | *.mo
55 | *.pot
56 |
57 | # Django stuff:
58 | *.log
59 | local_settings.py
60 | db.sqlite3
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | target/
74 |
75 | # Jupyter Notebook
76 | .ipynb_checkpoints
77 |
78 | # pyenv
79 | .python-version
80 |
81 | # celery beat schedule file
82 | celerybeat-schedule
83 |
84 | # SageMath parsed files
85 | *.sage.py
86 |
87 | # Environments
88 | .env
89 | .venv
90 | env/
91 | venv/
92 | ENV/
93 | env.bak/
94 | venv.bak/
95 |
96 | # Spyder project settings
97 | .spyderproject
98 | .spyproject
99 |
100 | # Rope project settings
101 | .ropeproject
102 |
103 | # mkdocs documentation
104 | /site
105 |
106 | # mypy
107 | .mypy_cache/
108 |
109 | # Dolphin file manager
110 | .directory
111 |
112 | # tex
113 | *.aux
114 | *.fls
115 | *.log
116 | *.out
117 | *.toc
118 | *.xdv
119 | *.fdb_latexmk
120 |
121 | # ETABS
122 | *.$et
123 | *.ico
124 | *.ebk
125 |
126 | # test
127 | test/etabs_api/test.*
128 |
129 | # FreeCAD backup files
130 | *.FCStd1
131 |
132 | # protect from users
133 | # OSAFEGui.py
134 | # !OSAFEGui.pyc
135 | # check_legal.py
136 | # !check_legal.pyc
137 |
138 |
--------------------------------------------------------------------------------
/Init.py:
--------------------------------------------------------------------------------
1 | import FreeCAD
2 |
3 | FreeCAD.addImportType("CSI SAFE (*.xls *.xlsx)", "old_punch.geom")
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FreeCAD Civil Foundation Model Workbench
2 | A Workbench in [FreeCAD](https://freecadweb.org) for creating foundation model in [CSI SAFE](https://www.csiamerica.com/products/safe) from [CSI ETABS](https://www.csiamerica.com/products/etabs) Model. It also can Import [CSI SAFE](https://www.csiamerica.com/products/safe) model into FreeCAD and calculate Shear punching of columns according to ACI 318-19.
3 |
4 | 
5 |
6 | ## Dependencies
7 | - This Addon/workbench runs on:
8 | - [x] Most up to date stable release
9 | - [x] Most up to date development release
10 | - [x] Python 3 compatible
11 | - [x] Qt5 compatible
12 | - [ ] Qt5 and Qt6 compatible (uses "import PySide" rather than "import PySide2")
13 | - [x] Backward compatible with 0.19 version of FC.
14 | - [x] 3rd party dependencies:
15 | - [x] numpy
16 | - [x] scipy
17 | - [x] pandas
18 | - [x] git
19 | - [x] comtypes
20 |
21 |
22 |
23 | ## Installation
24 |
25 | ### Addon Manager
26 | 1. Start the Addons Manager from menu Tools -> Addons manager
27 | 2. Locate and install the OSAFE addon
28 | 3. Restart FreeCAD, and switch to the OSAFE workbench
29 |
30 | ### Manually
31 | #### Windows
32 | You can download FreeCAD from below links and install it in windows. After installation, you must clear Civil folder in FreeCAD installation folder (ec. C:\Program Files\FreeCAD 0.19\Mod\Civil) and then clone this two repositories .
33 |
34 | https://github.com/ebrahimraeyat/OSAFE.git
35 | https://github.com/ebrahimraeyat/etabs_api.git
36 |
37 | [link1](https://github.com/ebrahimraeyat/OSAFE/releases/tag/v0.9)
38 | [link2](https://mega.nz/file/sUlAQaoA#SvTKQu_HswPNQxW9wT8PlCxLGXBZbBH_F-xp6A_bsps)
39 |
40 | #### Debian 10 (Buster)
41 |
42 | ```bash
43 | $ sudo apt install freecad-python3
44 | $ sudo update-alternatives --set freecad /usr/lib/freecad/bin/freecad-python3
45 | $ sudo apt install git python3-pandas
46 | $ mkdir -p $HOME/.FreeCAD/Mod
47 | $ cd $HOME/.FreeCAD/Mod
48 | $ git clone https://github.com/ebrahimraeyat/OSAFE.git
49 | $ git clone https://github.com/ebrahimraeyat/etabs_api.git
50 | ```
51 |
52 | ## Discussion
53 | Forum thread to discuss this workbench can be found in the [FreeCAD Subforums](https://forum.freecadweb.org/viewtopic.php?f=24&t=31813#p264539)
54 |
55 | ## Contribute
56 | Pull Requests are welcome. Please feel free to discuss them on the forum thread.
57 |
--------------------------------------------------------------------------------
/check_legal.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import base64
4 | import subprocess
5 | from pathlib import Path
6 |
7 |
8 | class CheckLegalUse:
9 |
10 | def __init__(self,
11 | filename,
12 | gist_url,
13 | dir_name='punch',
14 | n=1,
15 | ):
16 | import FreeCAD
17 | freecad_dir = Path(FreeCAD.ConfigGet("UserAppData"))
18 | if not freecad_dir.exists():
19 | freecad_dir.mkdir()
20 | application_dir = freecad_dir / dir_name
21 | if not application_dir.exists():
22 | application_dir.mkdir()
23 | self.filename = application_dir / filename
24 | self.gist_url = gist_url
25 | self.n = n
26 |
27 | def allowed_to_continue(self):
28 | if sys.platform == "win32":
29 | if not self.is_registered:
30 | self.serial = str(subprocess.check_output("wmic csproduct get uuid")).split("\\r\\r\\n")[1].split()[0]
31 | if not internet():
32 | return False, 'INTERNET'
33 |
34 | if not self.serial_number(self.serial):
35 | return False, 'SERIAL'
36 | else:
37 | self.register()
38 | return True, 'REGISTERED'
39 | return True, ''
40 | return True, ''
41 |
42 | def initiate(self):
43 | if not self.filename.exists():
44 | with open(self.filename, 'wb') as f:
45 | b = base64.b64encode('0-0'.encode('utf-8'))
46 | f.write(b)
47 |
48 | @property
49 | def is_registered(self):
50 | if not Path(self.filename).exists():
51 | self.initiate()
52 | return True
53 | else:
54 | text = self.get_registered_numbers()
55 | if text[0] == 1 or text[1] <= self.n:
56 | return True
57 | else:
58 | return False
59 |
60 | def get_registered_numbers(self):
61 | if not Path(self.filename).exists():
62 | self.initiate()
63 | with open(self.filename, 'rb') as f:
64 | b = f.read()
65 | text = base64.b64decode(b).decode('utf-8').split('-')
66 | return int(text[0]), int(text[1])
67 |
68 | def add_using_feature(self):
69 | if not Path(self.filename).exists():
70 | self.initiate()
71 | with open(self.filename, 'rb') as f:
72 | b = f.read()
73 | text = base64.b64decode(b).decode('utf-8').split('-')
74 | text[1] = str(int(text[1]) + 1)
75 | text = '-'.join(*[text])
76 | with open(self.filename, 'wb') as f:
77 | b = base64.b64encode(text.encode('utf-8'))
78 | f.write(b)
79 | return
80 |
81 | def register(self):
82 | if not Path(self.filename).exists():
83 | self.initiate()
84 | with open(self.filename, 'rb') as f:
85 | b = f.read()
86 | text = base64.b64decode(b).decode('utf-8').split('-')
87 | text[0] = '1'
88 | text = '-'.join([*text])
89 | with open(self.filename, 'wb') as f:
90 | b = base64.b64encode(text.encode('utf-8'))
91 | f.write(b)
92 |
93 | def serial_number(self, serial):
94 | import urllib.request
95 | response = urllib.request.urlopen(self.gist_url)
96 | data = response.read() # a `bytes` object
97 | text = data.decode('utf-8')
98 | return serial in text
99 |
100 | def internet(host="8.8.8.8", port=53, timeout=3):
101 | import socket
102 | try:
103 | socket.setdefaulttimeout(timeout)
104 | socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
105 | return True
106 | except Exception as ex:
107 | # print(ex.message)
108 | return False
109 |
--------------------------------------------------------------------------------
/civilwelcome.py:
--------------------------------------------------------------------------------
1 | import os
2 | import FreeCAD
3 | import FreeCADGui
4 |
5 | from PySide2 import QtCore, QtGui
6 |
7 |
8 | def QT_TRANSLATE_NOOP(ctx, txt): return txt
9 |
10 |
11 | class CivilWelcome:
12 |
13 | def GetResources(self):
14 | return {'Pixmap': os.path.join(os.path.dirname(__file__), "Images", "civil_welcom.svg"),
15 | 'MenuText': QT_TRANSLATE_NOOP("Civil_welcome", "Civil welcome screen"),
16 | 'ToolTip': QT_TRANSLATE_NOOP("Civil_welcome", "Show the Civil workbench welcome screen")}
17 |
18 | def Activated(self):
19 | self.form = FreeCADGui.PySideUic.loadUi(os.path.join(os.path.dirname(__file__), "ui", "civil_welcome.ui"))
20 | self.form.image.setPixmap(QtGui.QPixmap(os.path.join(os.path.dirname(__file__), "images", "banner.jpg")))
21 |
22 | result = self.form.exec_()
23 | # if result:
24 | # FreeCADGui.runCommand("Civil_Setup")
25 |
26 | FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OSAFE").SetBool("FirstTime", False)
27 |
--------------------------------------------------------------------------------
/compile.py:
--------------------------------------------------------------------------------
1 | import os
2 | import compileall
3 | import shutil
4 |
5 | from pathlib import Path
6 |
7 | shutil.rmtree(Path("__pycache__"))
8 | compileall.compile_file('OSAFEGui.py')
9 | shutil.copy(Path('__pycache__') / 'OSAFEGui.cpython-38.pyc', Path('OSAFEGui.pyc'))
--------------------------------------------------------------------------------
/help/cover.tex:
--------------------------------------------------------------------------------
1 | \pagenumbering{Roman} % a, b, c, ...
2 | \thispagestyle{empty}
3 | % نحوه درج کردن لوگوی دانشگاه
4 | \begin{figure*}[!h]
5 | \centerline{\includegraphics[width=4cm]{logo}}
6 | %\caption{}
7 | \end{figure*}
8 | \begin{center}
9 | %دستوری برای کم کردن فاصله بین لوگو و خط پایین آن
10 | \vspace{-.8cm}
11 |
12 | % {\large پژوهشگاه بین المللی زلزله شناسی و مهندسی زلزله}
13 | %دستوری برای تعیین فاصله بین دو خط
14 |
15 |
16 | \\[1cm]
17 | بنام خدا
18 | \\[1cm]
19 | راهنمای کاربری
20 | \\[.8cm]
21 | % {\nastaliq
22 | \begin{Huge}
23 | نرم افزار برش پانچ
24 | \end{Huge}
25 |
26 | \\[.5cm]
27 | \begin{latin}
28 | \textbf{Ver. 0.9}
29 | \end{latin}
30 |
31 |
32 |
33 | \begin{figure}[ht]
34 | \centering
35 | \includegraphics[width=\linewidth]{figures/punch}
36 | % \caption{DL, units:[m,kN]}
37 | % \label{dl-unitsmkn}
38 | \end{figure}
39 |
40 | \\[1cm]{ توسعه دهنده:}
41 | \\[.3cm]
42 | \textbf{{\large \developer}}
43 |
44 | % \\[2cm]{کارفرما}
45 | % \\[.3cm]
46 | % \textbf{{\large \karfarma}}
47 | % \\ \textit{\address}
48 |
49 | \\[1.cm]
50 | \today
51 | \end{center}
52 | %\maketitle
53 | %دستوری برای رفتن به صفحه جدید
54 | \newpage
55 | \thispagestyle{empty}
56 | % \pagenumbering{Roman} % i, ii, iii, iv, ...
57 | \setcounter{page}{1}
58 | \tableofcontents
59 | % \listoffigures
60 | % \listoftables
61 | \newpage
62 |
--------------------------------------------------------------------------------
/help/export.tex:
--------------------------------------------------------------------------------
1 | \section{ذخیره نتایج خروجی}
2 | برای گرفتن خروجی از نرم افزار، میتوانید از آیکون های مرتبط برای فرمت های مختلف استفاده کنید. در حال حاضر نرم افزار قادر به خروجی نتایج گرافیکی پانچ ها به فرمت عکس،
3 | پی دی اف و اتوکد می باشد. همچنین محاسبات پانچ برای تمامی ترکیب بارها را میتوان به صورت فایل اکسل ذخیره نمود. اگر آیکن ها وجود ندارند و یا اینکه منوی
4 | \lr{Civil}
5 | در منوهای نرم افزار موجود نیست باید ابتدا طبق بخش
6 | \ref{sec:loadingcivil}
7 | ورک بنچ را فعال نمایید.
8 |
9 | \begin{figure}[H]
10 | \centering
11 | \includegraphics{figures/export}
12 | \caption{منو و آیکن های خروجی نرم افزار}
13 | \end{figure}
--------------------------------------------------------------------------------
/help/faq.tex:
--------------------------------------------------------------------------------
1 | \newpage
2 | \section{پرسش های متداول\label{faq}}
3 |
4 | در این بخش برخی از سوالات متداول که کاربران میپرسند به مرور زمان اضافه میشود.
5 |
6 | \begin{question}{مشخصات فنداسیون یا پانچ برای من نمایش داده نمیشود.}
7 | \true
8 | اگر با کلیک روی فنداسیون یا هر یک از ستونها در محیط سه بعدی یا قسمت بالایی جدول
9 | \lr{Combo View}
10 | مشخصات فنداسیون یا پانچ ها قابل مشاهده نیستند، در قسمت پایین جدول مطمئن شوید که تب
11 | \lr{Data}
12 | فعال باشد، مطابق شکل
13 | \ref{fig:dataview}.
14 | \end{question}
15 |
16 | \begin{figure}[H]
17 | \centering
18 | \includegraphics{figures/dataview}
19 | \caption{تنظیم نمایش مشخصات با انتخاب تب \lr{Data}}
20 | \label{fig:dataview}
21 | \end{figure}
22 |
23 |
24 | \begin{question}{چطور هر بار که نرم افزار را باز میکنم به طور خودکار
25 | \lr{Civil}
26 | لود شود؟}
27 | \true
28 | برای این کار باید از منوی
29 | $Edit \rightarrow Preferences$
30 | پنجره تنظیمات نرم افزار را باز کنید. مطابق شکل
31 | \ref{fig:autoload}
32 | ، در تب
33 | \lr{General}
34 | قسمت
35 | \lr{Start up}
36 | ورک بنچ
37 | \lr{Civil}
38 | را انتخاب کنید و سپس کلید تایید را بزنید. از این پس بعد از اجرای نرم افزار به طور خودکار ورک بنچ
39 | \lr{Civil}
40 | لود میشود.
41 | \end{question}
42 |
43 |
44 | \begin{figure}[H]
45 | \centering
46 | \includegraphics[width=.7\linewidth]{figures/autoload}
47 | \caption{تنظیم لود شدن خودکار ورک بنچ \lr{Civil} بعد از هر اجرا}
48 | \label{fig:autoload}
49 | \end{figure}
--------------------------------------------------------------------------------
/help/figures/assign.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/assign.png
--------------------------------------------------------------------------------
/help/figures/autoload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/autoload.png
--------------------------------------------------------------------------------
/help/figures/civil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/civil.png
--------------------------------------------------------------------------------
/help/figures/columnedit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/columnedit.png
--------------------------------------------------------------------------------
/help/figures/comboview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/comboview.png
--------------------------------------------------------------------------------
/help/figures/dataview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/dataview.png
--------------------------------------------------------------------------------
/help/figures/excel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/excel.png
--------------------------------------------------------------------------------
/help/figures/excel2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/excel2.png
--------------------------------------------------------------------------------
/help/figures/export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/export.png
--------------------------------------------------------------------------------
/help/figures/geometry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/geometry.png
--------------------------------------------------------------------------------
/help/figures/geometry2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/geometry2.png
--------------------------------------------------------------------------------
/help/figures/import_model_from_etabs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/import_model_from_etabs.png
--------------------------------------------------------------------------------
/help/figures/make_auto_strip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/make_auto_strip.png
--------------------------------------------------------------------------------
/help/figures/punch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/figures/punch.png
--------------------------------------------------------------------------------
/help/freecad.tex:
--------------------------------------------------------------------------------
1 | \section{محاسبه برش پانچ در \lr{FreeCAD}}
2 |
3 | \subsection{بارگذاری ورک بنچ \lr{Civil}\label{sec:loadingcivil}}
4 | بعد از باز کردن نرم افزار
5 | \lr{FreeCAD}
6 | ، مطابق شکل
7 | \ref{fig:civil-workbench}
8 | با کلیک روی منوی کرکره ای ورک بنچ ها، از لیست موجود
9 | \lr{Civil}
10 | را انتخاب کنید. با این کار منو و آیکون های نرم افزار برش پانچ ظاهر میشوند. برای اینکه هر دفعه پس از بازکردن نرم افزار نیاز به این کار نداشته باشید به قسمت
11 | \ref{faq}
12 | مراجعه کنید.
13 |
14 | \begin{figure}[H]
15 | \centering
16 | \includegraphics[width=\linewidth]{figures/civil}
17 | \caption{بارگذاری ورک بنچ \lr{Civil}}
18 | \label{fig:civil-workbench}
19 | \end{figure}
20 | \subsection{بازکردن فایل اکسل}
21 | برای فراخوانی فایل اکسلی که در بخش
22 | \ref{sec:prepare-safe}
23 | ساختیم، کافیست که آنرا مثل یک فایل اکسل در نرم افزار باز کنید. یعنی از منوی
24 | $File \rightarrow Open$
25 | این کار را انجام دهید. در این مرحله حتی نیاز به فراخوانی ورک بنچ
26 | \lr{Civil}
27 | نمی باشد. بعد از چند لحظه فنداسیون داخل نرم افزار بارگذاری شده و محاسبات پانچ برای تمامی ستونها صورت میگیرد.
28 |
29 | \subsection{ذخیره پروژه}
30 | در ورژن جدید میتوانید به سادگی مثل سایر نرم افزارها پروژه را ذخیره و باز کنید. بعد از بازکردن پروژه های ذخیره شده میتوانید ویرایش های لازم را انجام دهید. این قابلیت در
31 | ورژن های قبلی نرم افزار موجود نبود.
--------------------------------------------------------------------------------
/help/help.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/help/help.pdf
--------------------------------------------------------------------------------
/help/help.tex:
--------------------------------------------------------------------------------
1 | \documentclass[hidelinks, a4paper,twoside]{punch_report}
2 | \usepackage{array, boldline, makecell, booktabs}
3 | \newcommand\btrule[1]{\specialrule{#1}{0pt}{0pt}}
4 | \usepackage{colortbl}
5 | \usepackage{multicol,caption} % three-column layout
6 | \usepackage[font={footnotesize}]{caption}
7 | \usepackage{xcolor}
8 | \usepackage{amsmath}
9 | % \usepackage{ae}
10 | \usepackage{geometry}
11 | \usepackage{multirow}
12 | \usepackage{siunitx}
13 | \usepackage[title]{appendix}
14 | \usepackage{longtable}
15 | \usepackage{hyperref}
16 | \usepackage{flafter}
17 | \usepackage{afterpage}
18 | \usepackage{varioref}
19 | % \usepackage[utf8]{inputenc}
20 | \usepackage{graphicx}
21 | \usepackage{setspace}
22 | \setstretch{2}
23 | \usepackage[many]{tcolorbox}
24 | \usepackage{float}
25 | \usepackage{xcolor}
26 | \hypersetup{
27 | colorlinks,
28 | linkcolor={blue!70!black},
29 | citecolor={blue!50!black},
30 | urlcolor={blue!80!black}
31 | }
32 | \usepackage{xepersian-multiplechoice}
33 | \usepackage{xepersian}
34 | \settextfont[Scale=1.4]{XB Niloofar}
35 | % \setlatintextfont[Scale=1.3]{Times New Roman}
36 | %\usepackage{draftwatermark}
37 | %\SetWatermarkText{Draft}
38 | %\SetWatermarkScale{1}
39 |
40 | % \newenvironment{Figure}
41 | % {\par\medskip\noindent\minipage{\linewidth}}
42 | % {\endminipage\par\medskip}
43 |
44 |
45 | % \title{دفترچه محاسبات سازه}
46 | % \newcommand{\punch}{نرم افزار برش پانچ}
47 | % \newcommand{\address}{شهرک شکوهیه فاز 2 خ بابایی خ تهرانی مقدم نبش فرعی 5}
48 | % \author{ابراهیم رعیت رکن آبادی}
49 | % % \date{}
50 | % \today{}
51 |
52 | %\vspace{3cm}\textbf{NOTE: This preliminary report is simply deemed suitable for the purpose of pre-dimensioning the structures addressed and obtaining the loads transmitted by them upon the foundation. The equipment modelling doesn't reflect its final geometric characteristics.}}
53 | % \renewcommand{\revision}{1.0}
54 |
55 | \begin{document}
56 | % \begin{center}
57 | % بنام خدا \newline
58 | % \maketitle
59 | % \vspace{10cm}
60 | % مالک: شرکت سلامت گستران پردیس پارت
61 | % \newline
62 | % پلاک ثبتی:
63 | % \end{center}
64 |
65 |
66 | % \newpage
67 | % \renewcommand{\abstractname}{Executive Summary}.
68 | % \maxdeadcycles=200
69 |
70 | % %\maketitle
71 | % \tableofcontents
72 | % \listoftables
73 | % \listoffigures
74 | % \newpage
75 | \input{cover}
76 | \pagenumbering{arabic}
77 | \input{introduction}
78 | % \begin{twocolumn}
79 | \input{safe}
80 | \input{freecad}
81 | \input{modify}
82 | \input{export}
83 | \input{update}
84 | \input{faq}
85 |
86 | % \end{twocolumn}
87 | % \section{Combination of loads}
88 | % \input{combinations.tex}
89 | % \input{xc_design_technique.tex}
90 |
91 | % \clearpage
92 | % \input{appendix}
93 |
94 | % \clearpage
95 | % -----
96 | %------------------------------------------------
97 |
98 | %----------------------------------------------------------------------------------------
99 | % REFERENCE LIST
100 | %----------------------------------------------------------------------------------------
101 | %\phantomsection
102 | %\nocite{OpenSeesManual,FeynmanVolI,Thomson} % writes also non-cited references
103 | % \nocite{*}
104 | % \bibliography{jubail} %file .bib
105 | % \bibliographystyle{plain} %normal style - listed in ABC order and labeled numerically
106 | %\bibliographystyle{unsrt} %same as plain except entries appear in order of citation
107 |
108 | % to compile the document run:
109 | % latex structural_design_report to create the .aux file
110 | % bibtex structural_design_report to get some of the citations and create a .bbl file
111 | % latex structural_design_report again so that the cross references between latex file and bibliography
112 | % are correct
113 |
114 | %----------------------------------------------------------------------------------------
115 |
116 | \end{document}
117 |
--------------------------------------------------------------------------------
/help/import_model.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | undefined
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
ورود مدل به داخل نرم افزار
30 |
با زدن آیکن ایتبز پنجره زیر برای کاربر نمایش داده میشود. قبل از این کار سازه حتما باید آنالیز شده باشد، نیاز نیست که کار طراحی انجام شده باشد.
31 |
32 |
ورود تیرها و ستونها
33 |
شما میتوانید تیرهای یک طبقه را به داخل مدل فری کد وارد کنید. برای این کار میتوانید طبقه مورد نظر خود را از لیستانتخاب کنید.
34 |
سه گزینه برای تیرها داریم:
35 |
36 | همه تیرها: همه تیرهای طبقه را وارد میکند
37 | تیرهای انتخاب شده: فقط تیرهای انتخاب شده در آن طبقه را وارد میکند
38 | همه تیرها بجز تیرهای انتخاب شده: به غیر از تیرهای انتخاب شده، تمام تیرهای یک طبقه را وارد میکند.
39 | در این قسمت اگر نیم طبقه دارید، بهتر است در مدل ایتبز، تیرهای نیم طبقه را انتخاب کنید و از گزینه سوم استفاده کنید. چون در غیر اینصورت ممکن است چند تیر رویهم قرار بگیرند و در مراحل بعدی نرم افزار دچار ایراد شود. اگر هم چند تیر رویهم وارد مدل شد، میتوانید بعد از ورود مدل نیز براحتی آنها را پاک کنید.
40 |
41 |
ساخت فایل ورودی سیف
42 |
نرم افزار اسیف قادر است فایل ورودی سیف را به طور خودکار ایجاد نماید. یعنی دیگر کاربر نیاز به گرفتن خروجی فایل سیف از نرم افزار ایتبز نمی باشد.
43 | نرم افزار به طور خودکار تمام گره هایی که مقید شده اند را به همراه عکس العمل های آنها به داخل نرم افزار منتقل میکند. در این قسمت اگر فنداسیون در ۲ یا چند سطح باشد، تمام گره ها در ترازی که کاربر در کادر مربوطه وارد میکند ایجاد میشود.
44 |
بعد از تایید این پنجره عملیات انتقال مدل از ایتبز به داخل نرم افزار شروع میشود.
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/help/import_model.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ورود مدل به داخل نرم افزار
4 |
5 | با زدن آیکن ایتبز پنجره زیر برای کاربر نمایش داده میشود. قبل از این کار سازه حتما باید آنالیز شده باشد، نیاز نیست که کار طراحی انجام شده باشد.
6 |
7 | 
8 |
9 | ## ورود تیرها و ستونها
10 | شما میتوانید تیرهای یک طبقه را به داخل مدل فری کد وارد کنید. برای این کار میتوانید طبقه مورد نظر خود را از لیستانتخاب کنید.
11 |
12 | سه گزینه برای تیرها داریم:
13 |
14 | - همه تیرها: همه تیرهای طبقه را وارد میکند
15 | - تیرهای انتخاب شده: فقط تیرهای انتخاب شده در آن طبقه را وارد میکند
16 | - همه تیرها بجز تیرهای انتخاب شده: به غیر از تیرهای انتخاب شده، تمام تیرهای یک طبقه را وارد میکند.
17 | در این قسمت اگر نیم طبقه دارید، بهتر است در مدل ایتبز، تیرهای نیم طبقه را انتخاب کنید و از گزینه سوم استفاده کنید. چون در غیر اینصورت ممکن است چند تیر رویهم قرار بگیرند و در مراحل بعدی نرم افزار دچار ایراد شود. اگر هم چند تیر رویهم وارد مدل شد، میتوانید بعد از ورود مدل نیز براحتی آنها را پاک کنید.
18 |
19 | ## ساخت فایل ورودی سیف
20 | نرم افزار اسیف قادر است فایل ورودی سیف را به طور خودکار ایجاد نماید. یعنی دیگر کاربر نیاز به گرفتن خروجی فایل سیف از نرم افزار ایتبز نمی باشد.
21 | نرم افزار به طور خودکار تمام گره هایی که مقید شده اند را به همراه عکس العمل های آنها به داخل نرم افزار منتقل میکند. در این قسمت اگر فنداسیون در ۲ یا چند سطح باشد، تمام گره ها در ترازی که کاربر در کادر مربوطه وارد میکند ایجاد میشود.
22 |
23 | بعد از تایید این پنجره عملیات انتقال مدل از ایتبز به داخل نرم افزار شروع میشود.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/help/introduction.tex:
--------------------------------------------------------------------------------
1 | \section*{مقدمه}
2 |
3 | محاسبه برش پانچ در نرم افزار سیف به صورت صحیح همیشه یکی از دغدغه های مهندسین عمران بوده است. خود من همیشه برای محاسبه پانچ با مشکل روبرو می شدم. بعد از آشنایی با نرم افزار
4 | \lr{FreeCAD}
5 | و بررسی قابلیت های آن تصمیم گرفتم نرم افزار برش پانچ را با استفاده از ابزارهای قدرتمند این نرم افزار ایجاد کنم. مهمترین مشکل این کار، تشخیص درست صفحات پانچ و موقعیت ستون بود که به لطف خدا الگوریتم
6 | بسیار دقیقی برای این کار نوشتم که در تمامی موارد صفحات و موقعیت ستون ها را به درستی تشخیص میدهد.
7 |
8 |
9 | نرم افزار حاضر، نرم افزاری کدباز برای محاسبه برش پانچ فنداسیون با استفاده از خروجی نرم افزار سیف می باشد. این نرم افزار با تلاش های شبانه روزی تهیه شده است و در توسعه آن سعی شده است که ضمن داشتن رابط کاربری آسان،
10 | نتایج نرم افزار از دقت بسیار بالایی برخوردار باشد. امیدوارم که برای مهندسین عزیز مفید باشد.
11 |
12 |
13 |
14 | کانال تلگرام: \lr{@civiltools} \newline
15 | آی دی تلگرام: \lr{@roknabadi}
16 |
17 | \newpage
--------------------------------------------------------------------------------
/help/make_auto_strip.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | undefined
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
ایجاد استریپ ها
30 |
برای ساخت استریپ ها، فنداسیون باید ایجاد شده باشد. در این مرحله بعد از انتخاب آیکن ساخت
31 | استریپ، پنجره زیر نمایش داده میشود:
32 |
33 |
ساخت استریپ در فنداسیون های گسترده
34 |
در فنداسیون های گسترده شما میتوانید موارد زیر را انتخاب کنید:
35 |
36 | نام نوارها در راستای x, y
37 | عرض نوارها در راستای x, y
38 | با انتخاب Equal Width عرض نوارها به طور مساوی تقسیم بندی میشود، در غیر اینصورت تمام نوارها با عرض انتخابی کاربر ایجاد میشود، به غیر از نوار آخری، که عرض باقیمانده به آن نوار اختصاص داده میشود.
39 |
40 |
ایجاد استریپ در فنداسیون های نواری
41 |
در فنداسیون های نواری، نرم افزار به طور خودکار از روی بیس فنداسیون ها که در ابتدا ترسیم شده اند، استفاده میکند و نیاز به وارد کردن عرض و یا نام نوارها نمی باشد.
42 |
43 | گزینه Draw Lateral برای ترسیم نوارهای عرضی استفاده میشود که در حال حاضر غیرفعال می باشد.
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/help/make_auto_strip.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | #
ایجاد استریپ ها
4 | برای ساخت استریپ ها، فنداسیون باید ایجاد شده باشد. در این مرحله بعد از انتخاب آیکن ساخت
5 | استریپ، پنجره زیر نمایش داده میشود:
6 |
7 | 
8 |
9 | ##
ساخت استریپ در فنداسیون های گسترده
10 |
11 | در فنداسیون های گسترده شما میتوانید موارد زیر را انتخاب کنید:
12 |
13 | - نام نوارها در راستای x, y
14 | - عرض نوارها در راستای x, y
15 | - با انتخاب Equal Width عرض نوارها به طور مساوی تقسیم بندی میشود، در غیر اینصورت تمام نوارها با عرض انتخابی کاربر ایجاد میشود، به غیر از نوار آخری، که عرض باقیمانده به آن نوار اختصاص داده میشود.
16 |
17 | ##
ایجاد استریپ در فنداسیون های نواری
18 |
19 | در فنداسیون های نواری، نرم افزار به طور خودکار از مشخصات بیس فنداسیون ها که در ابتدا ترسیم شده اند، برای رسم استریپ ها استفاده میکند و نیاز به وارد کردن عرض و یا نام نوارها نمی باشد.
20 |
21 | - گزینه Draw Lateral برای ترسیم نوارهای عرضی استفاده میشود که در حال حاضر غیرفعال می باشد.
--------------------------------------------------------------------------------
/help/modify.tex:
--------------------------------------------------------------------------------
1 | \section{تغییر مشخصات پانچ ها}
2 |
3 | نرم افزار برش پانچ به گونه ای نوشته شده است که تقریبا در تمامی موارد پانچ ستونها را بدرستی تشخیص داده و نسبت آنها را محاسبه میکند. با این حال برای اینکه کاربر بتواند کنترل بیشتری روی
4 | پارامترهای مختلف محاسبه پانچ داشته باشد، ارتفاع فنداسیون، مقاومت بتن فنداسیون، ابعاد ستونها و موقعیت ستونها در نرم افزار قابل ویرایش هستند.
5 | با تغییر هر یک از پارامترها پانچ تمامی ستونها مجددا محاسبه میشود. ممکن است ستونی که به صورت کنار شناخته شده است با افزایش ضخامت فنداسیون به صورت گوشه شناخته شود و در نتیجه
6 | نسبت تنش پانچ آن افزایش یابد!
7 |
8 | \subsection{تغییر مشخصات فنداسیون}
9 | ضخامت، کاور و مقاومت بتن فنداسیون را میتوان در نرم افزار تغییر داد. برای این کار کافیست که در محیط سه بعدی نرم افزار روی فنداسیون کلیک کنید. با این کار در جدول سمت چپ با نام
10 | \lr{Combo View}
11 | مشخصات فنداسیون به نمایش در می آید (شکل
12 | \ref{fig:comboview}
13 | ). اگر مشخصات قابل رویت نیست به بخش سوالات متداول مراجعه کنید.
14 | % \ref{faq:dataview}
15 |
16 | \begin{figure}[H]
17 | \centering
18 | \includegraphics{figures/comboview}
19 | \caption{تغییر مشخصات فنداسیون}
20 | \label{fig:comboview}
21 | \end{figure}
22 |
23 | \subsection{تغییر مشخصات ستونها}
24 | ابعاد و موقعیت ستونها را میتوان تغییر داد. برای این کار در محیط سه بعدی نرم افزار روی هر کدام از ستونها که قصد تغییر مشخصات آنرا دارید کلیک کنید.
25 | با این کار در جدول سمت چپ مشخصات ستون ظاهر میشود که میتوان ابعاد ستون،
26 | $b_x, b_y$
27 | و موقعیت ستون،
28 | \lr{Location}
29 | را تغییر داد. برای تغییر ابعاد ستون کافیست که عدد مورد نظر خود را برای ابعاد ستون وارد کنید.
30 | برای تغییر موقعیت ستون ابتدا باید پارامتر
31 | \lr{user modified}
32 | را از حالت
33 | \lr{false}
34 | به
35 | \lr{true}
36 | تغییر دهید و سپس موقعیت جدید ستون را با پارامتر
37 | \lr{Location}
38 | تغییر دهید. دقت کنید که فقط میتوان از پانچ وسط به کنار و گوشه
39 | و از پانچ کنار به گوشه تغییر موقعیت داد. چون باید صفحات مناسب پانچ برای تشخیص وجود داشته باشد.
40 | یعنی نرم افزار با تغییر موقعیت ستون، یک یا دو صفحه پانچ را حذف میکند، ولی نمیتوان صفحه ای که وجود ندارد را به آن اضافه نمود!
41 |
42 | \begin{itemize}
43 | \item نکته: بجای اینکه ویرایش را جدول کنار نرم افزار انجام دهید میتوانید با دابل کلیک روی اسم هر کدام از پانچ ها در قسمت بالایی جدول
44 | \lr{Combo View}
45 | این کار را انجام دهید. پس از دابل کلیک روی نام پانچ مورد نظر، یک پنجره مطابق شکل
46 | \ref{fig:columnedit}
47 | باز میشود که میتوانید موقعیت و ابعاد ستون را در آن تغییر دهید. در این پنجره نیز برای تغییر موقعیت ستون تیک مورد نظر را بزنید.
48 | \end{itemize}
49 |
50 | \begin{figure}[H]
51 | \centering
52 | \includegraphics{figures/columnedit}
53 | \caption{پنجره تغییر مشخصات ستون}
54 | \label{fig:columnedit}
55 | \end{figure}
56 |
--------------------------------------------------------------------------------
/help/punch_report.cls:
--------------------------------------------------------------------------------
1 | % This document class provides a simple memo for LaTeX users.
2 | % It is based on article.cls and inherits most of the functionality
3 | % that class.
4 | %
5 | % Author: Rob Oakes, Copyright 2010. Released under the LGPL, version 3.
6 | % A copy of the LGPL can be found at http://www.gnu.org/licenses/lgpl.html
7 |
8 | \NeedsTeXFormat{LaTeX2e}
9 | \ProvidesClass{punch_report}[2010/07/31 - Simple Report Class, Including Logo]
10 | \RequirePackage{palatino}
11 | \RequirePackage{fancyhdr}
12 | \RequirePackage{geometry}
13 | \RequirePackage{lastpage}
14 | \RequirePackage{svg}
15 |
16 | \newcommand{\revision}{0.0}
17 | \newcommand{\reportLogo}{\includesvg[height=10mm]{figures/punch}}
18 | %%\newcommand{\reportLogo}{\includesvg{xc_report_logo}}
19 |
20 | % Load the Base Class
21 | \LoadClassWithOptions{article}
22 | \usepackage{geometry}
23 | \geometry{hmargin={2.5cm,1.5cm},vmargin={3cm,3cm}}
24 |
25 | \pagestyle{fancy}
26 | \fancypagestyle{plain}{
27 | \fancyhf{} %anula los valores de fancy por defecto
28 |
29 | \fancyfoot[LE]{صفحه \thepage\ از \pageref{LastPage}}
30 | \fancyfoot[CE]{\reportLogo}
31 | % \fancyfoot[RE]{\emph{rev. \revision}}
32 |
33 | \fancyfoot[LO]{\emph{\date}}
34 | \fancyfoot[CO]{\reportLogo}
35 | \fancyfoot[RO]{صفحه \thepage\ از \pageref{LastPage}}
36 | \renewcommand{\headrulewidth}{0pt} %Dibuja una raya debajo de la cabecera
37 | \renewcommand{\footrulewidth}{0pt}
38 | }
39 |
40 | \renewcommand{\headrulewidth}{0pt} %Dibuja una raya debajo de la cabecera
41 | \renewcommand{\footrulewidth}{0pt}
42 | % \textheight= 22cm %%Espacio vertical para el texto.
43 | %\textwidth=16cm
44 | \marginparwidth=2mm
45 |
46 | \fancyhf{} %anula los valores de fancy por defecto
47 |
48 | \fancyhead[LE]{\textsc{\karfarma}}
49 | \fancyhead[RO]{\leftmark}
50 | \fancyhead[RO]{\textsc{\rightmark}}
51 |
52 | \fancyfoot[LE]{صفحه \thepage\ از \pageref{LastPage}}
53 | \fancyfoot[CE]{\reportLogo}
54 | % \fancyfoot[RE]{\emph{rev. \revision}}
55 |
56 | \fancyfoot[LO]{\emph{\date}}
57 | \fancyfoot[CO]{\reportLogo}
58 | \fancyfoot[RO]{صفحه \thepage\ از \pageref{LastPage}}
59 |
60 | \newcommand{\developer}{ابراهیم رعیت رکن آبادی}
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/help/safe.tex:
--------------------------------------------------------------------------------
1 | \section{ساخت فایل خروجی اکسل در سیف\label{sec:prepare-safe}}
2 | مراحلی که در زیر آمده است برای آماده سازی فایل نرم افزار برش پانچ کفایت میکند. بنابراین نیاز به انجام کار اضافی نیست. مثلا نیاز به تخصیص سختی خاک، المانهای ستون
3 | \lr{(Stiff)}
4 | و ... نمی باشد.
5 |
6 |
7 | \subsection{ترسیم هندسه پی}
8 | در این مرحله فقط هندسه پی مطابق شکل
9 | \ref{geometry}
10 | ترسیم می شود. سعی کنید در این مرحله تمیزکاری زیادی نکنید. منظورم این هست که
11 | \textbf{هم پوشانی}
12 | نوارهای فنداسیون چه در سیف و چه در نرم افزار برش پانچ مشکلی ایجاد نمیکند،
13 | بنابراین سعی نکنید که لبه های نوارها را بهم بچسبانید، بلکه اجازه دهید مقداری هم پوشانی در نوارها ایجاد شود.
14 | برای ترسیم پی های نواری میتوانید از
15 | \textbf{بازشو}
16 | هم استفاده کنید و نرم افزار برش پانچ با ترسیم بازشو مشکلی ندارد و محاسبات پانچ به درستی انجام میگیرد.
17 |
18 | \begin{figure}[H]
19 | \centering
20 | \includegraphics[scale=.6]{figures/geometry2}
21 | \caption{ترسیم هندسه پی در سیف}
22 | \label{geometry}
23 | \end{figure}
24 |
25 |
26 | \subsection{اختصاص مقطع به پی}
27 | در این مرحله از منوی
28 | $Assign \rightarrow Slab Data \rightarrow Properties$
29 | به هندسه ترسیم شده مقطع مناسب را اختصاص دهید (شکل
30 | \ref{assign}):
31 |
32 | \begin{figure}[H]
33 | \centering
34 | \includegraphics[scale=.6]{figures/assign}
35 | \caption{اختصاص مقطع به پی}
36 | \label{assign}
37 | \end{figure}
38 |
39 |
40 | \subsection{خروجی به اکسل}
41 | مطابق شکل
42 | \ref{excel}
43 | از منوی
44 | $File \rightarrow Export Model \rightarrow Excel $
45 | خروجی به اکسل را انتخاب کنید. مطابق شکل
46 | \ref{excel2}
47 | تیک بخش
48 | \lr{MODEL DEFINITION}
49 | را بزنید و
50 | در قسمت
51 | \lr{Select Load Patterns}
52 | تمامی الگوی بارها را انتخاب و واحد خروجی را
53 | $KN, mm, C$
54 | برگزینید. فایل را در محل دلخواه ذخیره کنید.
55 |
56 | \begin{figure}[H]
57 | \centering
58 | \includegraphics[width=.7\linewidth]{figures/excel}
59 | \caption{خروجی به اکسل}
60 | \label{excel}
61 | \end{figure}
62 |
63 | \begin{figure}[H]
64 | \centering
65 | \includegraphics[width=.7\linewidth]{figures/excel2}
66 | \caption{تنظیم پارامترهای خروجی فایل اکسل}
67 | \label{excel2}
68 | \end{figure}
--------------------------------------------------------------------------------
/help/update.tex:
--------------------------------------------------------------------------------
1 | \section{آپدیت نرم افزار}
2 | برای آپدیت به آخرین تغییرات نرم افزار کافیست که روی آیکن شکل چرخ دنده کلیک کنید. برای اولین بار احتمالا حدود ۲-۳ دقیقه برای آپدیت نرم افزار زمان نیاز است.
3 | بعد از اتمام نصب، پوشه
4 | \lr{Civil}
5 | در محل نصب نرم افزار را پاک کنید. به طور معمول پوشه
6 | \lr{Civil}
7 | در مسیر زیر قرار دارد:
8 |
9 | \begin{center}
10 |
11 | \lr{C:\textbackslash Program Files\textbackslash FreeCAD\textbackslash mod}
12 | \end{center}
13 |
14 |
15 | نرم افزار را مجددا راه اندازی کنید. برای آپدیت های بعدی نیاز به پاک کردن فایل نیست، چون اصلا فایلی وجود ندارد!
16 |
--------------------------------------------------------------------------------
/old_punch/Help.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/old_punch/Help.pdf
--------------------------------------------------------------------------------
/old_punch/foundraw/pyconcreteWelcome.py:
--------------------------------------------------------------------------------
1 | #***************************************************************************
2 | #* *
3 | #* Copyright (c) 2017 Yorik van Havre
*
4 | #* *
5 | #* This program is free software; you can redistribute it and/or modify *
6 | #* it under the terms of the GNU Lesser General Public License (LGPL) *
7 | #* as published by the Free Software Foundation; either version 2 of *
8 | #* the License, or (at your option) any later version. *
9 | #* for detail see the LICENCE text file. *
10 | #* *
11 | #* This program is distributed in the hope that it will be useful, *
12 | #* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 | #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 | #* GNU Library General Public License for more details. *
15 | #* *
16 | #* You should have received a copy of the GNU Library General Public *
17 | #* License along with this program; if not, write to the Free Software *
18 | #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
19 | #* USA *
20 | #* *
21 | #***************************************************************************
22 |
23 | """This module contains FreeCAD commands for the pyconcrete workbench"""
24 |
25 | import os
26 | import FreeCAD
27 | import FreeCADGui
28 |
29 | from PySide import QtCore, QtGui
30 |
31 |
32 | def QT_TRANSLATE_NOOP(ctx, txt): return txt # dummy function for the QT translator
33 |
34 |
35 | class PyconcreteWelcome:
36 |
37 | def GetResources(self):
38 |
39 | return {'Pixmap': os.path.join(os.path.dirname(__file__), "icons", "pyconcrete_Welcome.svg"),
40 | 'MenuText': QT_TRANSLATE_NOOP("pyconcrete_Welcome", "pyconcrete Welcome screen"),
41 | 'ToolTip': QT_TRANSLATE_NOOP("pyconcrete_Welcome", "Show the pyconcrete workbench welcome screen")}
42 |
43 | def Activated(self):
44 |
45 | # load dialog
46 | self.form = FreeCADGui.PySideUic.loadUi(os.path.join(os.path.dirname(__file__), "ui", "dialogWelcome.ui"))
47 |
48 | # set the title image
49 | self.form.image.setPixmap(QtGui.QPixmap(os.path.join(os.path.dirname(__file__), "icons", "banner.png")))
50 |
51 | # handle the tutorial link
52 | # QtCore.QObject.connect(self.form.label_4, QtCore.SIGNAL("linkActivated(QString)"), self.launchTutorial)
53 |
54 | # center the dialog over FreeCAD window
55 | mw = FreeCADGui.getMainWindow()
56 | self.form.move(mw.frameGeometry().topLeft() + mw.rect().center() - self.form.rect().center())
57 |
58 | # show dialog and run setup dialog afterwards if OK was pressed
59 | result = self.form.exec_()
60 | if result:
61 | FreeCADGui.runCommand("Pyconcrete_Setup")
62 |
63 | # remove first time flag
64 | FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Pyconcrete").SetBool("FirstTime", False)
65 |
66 | # def launchTutorial(self,link):
67 |
68 | # if hasattr(self,"form"):
69 | # self.form.hide()
70 | # FreeCADGui.runCommand("Pyconcrete_Tutorial")
71 |
--------------------------------------------------------------------------------
/old_punch/test_safe.py:
--------------------------------------------------------------------------------
1 | from safe import Safe
2 | import unittest
3 |
4 |
5 | class TestSafe(unittest.TestCase):
6 | def setUp(self):
7 | self.safe = Safe("test_files/sattari_safe.xlsx")
8 |
9 | def test_program_control(self):
10 | self.assertEqual(self.safe.program_name, "SAFE 2016")
11 | self.assertEqual(self.safe.version, "16.0.1")
12 | self.assertEqual(self.safe.curr_units.force, "N")
13 | self.assertEqual(self.safe.curr_units.length, " mm")
14 | self.assertEqual(self.safe.curr_units.temp, " C")
15 | self.assertEqual(self.safe.concrete_code, "ACI 318-14")
16 |
17 | def test_obj_geom_points(self):
18 | points = self.safe.obj_geom_points
19 | no_of_points = len(list(points.keys()))
20 | coord = points[29]
21 | self.assertEqual(no_of_points, 84)
22 | self.assertEqual(coord.x, 0)
23 | self.assertEqual(coord.y, 5.1)
24 | self.assertEqual(coord.z, 0)
25 | self.assertEqual(coord.special, True)
26 |
27 | coord = points[72]
28 | self.assertAlmostEqual(coord.x, 4.46, places=2)
29 | self.assertAlmostEqual(coord.y, 11.034, places=3)
30 | self.assertEqual(coord.z, 0)
31 | self.assertEqual(coord.special, False)
32 |
33 | def test_obj_geom_areas(self):
34 | areas = self.safe.obj_geom_areas
35 | no_of_areas = len(list(areas.keys()))
36 | self.assertEqual(no_of_areas, 6)
37 | point_numbers = areas[11]
38 | self.assertEqual(point_numbers, [76, 75, 73, 72])
39 |
40 | stiff = self.safe.obj_geom_stiff
41 | point_numbers = stiff[20]
42 | self.assertEqual(point_numbers, [112, 113, 114, 115])
43 |
44 | def test_point_loads(self):
45 | point_loads = self.safe.point_loads
46 | self.assertEqual(len(point_loads), 10)
47 | no_of_loads = len(list(point_loads[29]['loads'].keys()))
48 | self.assertEqual(no_of_loads, 27)
49 | # point 29
50 | load = point_loads[29]['loads']['Dead_ABOVE']
51 | self.assertAlmostEqual(load.fx, -6.667899, places=5)
52 | self.assertAlmostEqual(load.fy, -8.647991, places=5)
53 | self.assertAlmostEqual(load.fz, 284.2031, places=4)
54 | self.assertAlmostEqual(load.mx, 9.956049, places=5)
55 | self.assertAlmostEqual(load.my, -7.921433, places=5)
56 | self.assertAlmostEqual(load.mz, 0.004490824, places=9)
57 | self.assertEqual(point_loads[29]['xdim'], 400)
58 | self.assertEqual(point_loads[29]['ydim'], 400)
59 | # point 49 EYALL-0.3EX(3/3)_ABOVE load
60 | load = point_loads[49]['loads']['EYALL-0.3EX(3/3)_ABOVE']
61 | self.assertAlmostEqual(load.fx, -9.586596, places=5)
62 | self.assertAlmostEqual(load.fy, 37.83184, places=5)
63 | self.assertAlmostEqual(load.fz, 62.41515, places=5)
64 | self.assertAlmostEqual(load.mx, -113.0372, places=4)
65 | self.assertAlmostEqual(load.my, -31.61491, places=5)
66 | self.assertAlmostEqual(load.mz, 0.3031819, places=7)
67 | self.assertEqual(point_loads[49]['xdim'], 400)
68 | self.assertEqual(point_loads[49]['ydim'], 400)
69 |
70 | class TestSafe_safdari(unittest.TestCase):
71 | def setUp(self):
72 | self.safe = Safe("test_files/safdari.xlsx")
73 |
74 | def test_solid_slabs(self):
75 | solid_slabs = self.safe.solid_slabs
76 | slab_prop = solid_slabs['COL']
77 | self.assertEqual(slab_prop.type, 'Stiff')
78 | self.assertEqual(slab_prop.matProp, 'C35')
79 | self.assertEqual(slab_prop.thickness, 3000)
80 |
81 | def test_slab_prop_assignment(self):
82 | slab_prop_assignment = self.safe.slab_prop_assignment
83 | self.assertEqual(slab_prop_assignment[9], 'SLAB70')
84 | self.assertEqual(slab_prop_assignment[31], 'COL')
85 | self.assertEqual(slab_prop_assignment[56], 'SLAB55')
86 |
87 | def test_concrete_mat(self):
88 | concrete_mat = self.safe.concrete_mat
89 | self.assertAlmostEqual(concrete_mat['C35'], 3.56900667277847, places=10)
90 |
91 | class TestSafe_safdari(unittest.TestCase):
92 | def setUp(self):
93 | self.safe = Safe("test_files/davoodabadi_dynamic.xlsx")
94 |
95 | def test_obj_geom_all_areas(self):
96 | areas = self.safe.obj_geom_areas
97 | no_of_areas = len(list(areas.keys()))
98 | self.assertEqual(no_of_areas, 8)
99 | point_numbers = areas[12]
100 | self.assertEqual(point_numbers, [257, 256, 255, 254, 253])
101 |
102 | point_numbers = areas[11]
103 | self.assertEqual(point_numbers, [252, 251, 250, 249])
104 |
105 | point_numbers = areas[106]
106 | self.assertEqual(point_numbers, [465, 4, 461, 25, 462, 463, 464, 427, 428])
107 |
108 |
109 | def test_grid_lines(self):
110 | pass
111 | # grid_lines = self.safe.grid_lines()
112 | # no_of_x_grid_line = len(grid_lines['x'])
113 | # no_of_y_grid_line = len(grid_lines['y'])
114 | # self.assertEqual(no_of_x_grid_line, 5)
115 | # self.assertEqual(no_of_y_grid_line, 4)
116 |
117 | def test_load_cases(self):
118 | pass
119 |
120 | def test_load_combinations(self):
121 | pass
122 |
123 | def test_punching_shear(self):
124 | pass
125 |
126 | def test_slab_prop(self):
127 | pass
128 |
129 | def soil_prop(self):
130 | pass
131 |
132 |
133 |
--------------------------------------------------------------------------------
/osafe_draw/draw_beam.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 | from PySide2 import QtCore
4 | from PySide2.QtCore import QT_TRANSLATE_NOOP
5 |
6 | import FreeCAD
7 | import FreeCADGui as Gui
8 | import Draft
9 | import DraftVecUtils
10 |
11 | from draftutils.translate import translate
12 | from draftguitools.gui_lines import Line
13 |
14 |
15 | class Beam(Line):
16 | """Gui command for the Beam tool."""
17 |
18 | def __init__(self, wiremode=True):
19 | super().__init__()
20 | self.isWire = wiremode
21 |
22 | def GetResources(self):
23 | menu_text = QtCore.QT_TRANSLATE_NOOP(
24 | "osafe_draw_beam",
25 | "Beam")
26 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
27 | "osafe_draw_beam",
28 | "Draw Beam")
29 | path = str(
30 | Path(__file__).parent.parent / "osafe_images" / "beam.svg"
31 | )
32 | return {'Pixmap': path,
33 | 'MenuText': menu_text,
34 | 'ToolTip': tool_tip}
35 |
36 | def finish(self, closed=False, cont=False):
37 | """Terminate the operation and close the polyline if asked.
38 |
39 | Parameters
40 | ----------
41 | closed: bool, optional
42 | Close the line if `True`.
43 | """
44 | self.removeTemporaryObject()
45 | if self.oldWP:
46 | FreeCAD.DraftWorkingPlane = self.oldWP
47 | if hasattr(Gui, "Snapper"):
48 | Gui.Snapper.setGrid()
49 | Gui.Snapper.restack()
50 | self.oldWP = None
51 |
52 | if len(self.node) > 1:
53 | if closed == True:
54 | self.node.append(self.node[0])
55 | cmd_list = ['from osafe_objects.beam import make_beam']
56 | for p1, p2 in zip(self.node[:-1], self.node[1:]):
57 | if DraftVecUtils.equals(p1, p2):
58 | continue
59 | p1 = DraftVecUtils.toString(p1)
60 | p2 = DraftVecUtils.toString(p2)
61 | cmd_list.append(f'make_beam({p1}, {p2})')
62 | self.commit(translate("civil", "Create beam"),
63 | cmd_list)
64 | super(Line, self).finish()
65 | Gui.Selection.clearSelection()
66 | if self.ui and self.ui.continueMode:
67 | self.Activated()
--------------------------------------------------------------------------------
/osafe_draw/draw_slab.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 | from PySide2 import QtCore
4 |
5 | import FreeCAD
6 | import FreeCADGui as Gui
7 | import DraftVecUtils
8 |
9 | from draftutils.translate import translate
10 | from draftguitools.gui_lines import Line
11 |
12 |
13 | class Slab(Line):
14 | """Gui command for the Slab tool."""
15 |
16 | def __init__(self, wiremode=True):
17 | super().__init__()
18 | self.isWire = wiremode
19 |
20 | def GetResources(self):
21 | menu_text = QtCore.QT_TRANSLATE_NOOP(
22 | "civil_slab",
23 | "Create slab")
24 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
25 | "civil_slab",
26 | "Create slab")
27 | path = str(
28 | Path(__file__).parent.parent / "osafe_images" / "slab.svg"
29 | )
30 | return {'Pixmap': path,
31 | 'MenuText': menu_text,
32 | 'ToolTip': tool_tip}
33 |
34 | def finish(self, closed=False, cont=False):
35 | """Terminate the operation and close the polyline if asked.
36 |
37 | Parameters
38 | ----------
39 | closed: bool, optional
40 | Close the line if `True`.
41 | """
42 | self.removeTemporaryObject()
43 | if self.oldWP:
44 | FreeCAD.DraftWorkingPlane = self.oldWP
45 | if hasattr(Gui, "Snapper"):
46 | Gui.Snapper.setGrid()
47 | Gui.Snapper.restack()
48 | self.oldWP = None
49 |
50 | if len(self.node) > 2:
51 | Gui.addModule("Draft")
52 | # The command to run is built as a series of text strings
53 | # to be committed through the `draftutils.todo.ToDo` class.
54 |
55 | # Insert a Draft wire
56 | rot, sup, pts, fil = self.getStrings()
57 |
58 | _base = DraftVecUtils.toString(self.node[0])
59 | _cmd = 'Draft.makeWire'
60 | _cmd += '('
61 | _cmd += 'points, '
62 | _cmd += 'placement=pl, '
63 | _cmd += 'closed=' + str(closed) + ', '
64 | _cmd += 'face=' + fil + ', '
65 | _cmd += 'support=' + sup
66 | _cmd += ')'
67 | _cmd_list = [
68 | 'pl = FreeCAD.Placement()',
69 | 'pl.Rotation.Q = ' + rot,
70 | 'pl.Base = ' + _base,
71 | 'points = ' + pts,
72 | 'line = ' + _cmd,
73 | 'Draft.autogroup(line)',
74 | 'FreeCAD.ActiveDocument.recompute()',
75 | 'from osafe_objects.slab import make_slab',
76 | 'make_slab(line)',
77 | 'line.ViewObject.hide()',
78 | ]
79 | self.commit(translate("civil", "Create Slab"),
80 | _cmd_list)
81 | super(Line, self).finish()
82 | Gui.Selection.clearSelection()
83 | if self.ui and self.ui.continueMode:
84 | self.Activated()
85 |
86 | Gui.addCommand('civil_slab', Slab())
87 |
--------------------------------------------------------------------------------
/osafe_gui/gui_automatic_rebars.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 |
4 | from PySide2 import QtCore
5 | from PySide2.QtCore import QT_TRANSLATE_NOOP
6 |
7 | import FreeCAD
8 | import FreeCADGui as Gui
9 |
10 |
11 | class OsafeAutomaticRebar:
12 | """Gui command for the creating stirp automatically in mat foundations."""
13 |
14 | def GetResources(self):
15 | menu_text = QtCore.QT_TRANSLATE_NOOP(
16 | "osafe",
17 | "Auto Rebar")
18 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
19 | "osafe",
20 | "Create Rebars automatically from strips")
21 | path = str(
22 | Path(__file__).parent.parent / "osafe_images" / "osafe_rebar.svg"
23 | )
24 | return {'Pixmap': path,
25 | 'MenuText': menu_text,
26 | 'ToolTip': tool_tip}
27 |
28 | def Activated(self):
29 | from osafe_py_widgets import draw_automatic_rebars
30 | win = draw_automatic_rebars.Form()
31 | Gui.Control.showDialog(win)
32 |
33 | def IsActive(self):
34 | return not FreeCAD.ActiveDocument is None
35 |
36 | if FreeCAD.GuiUp:
37 | Gui.addCommand('osafe_automatic_rebars', OsafeAutomaticRebar())
--------------------------------------------------------------------------------
/osafe_images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/banner.jpg
--------------------------------------------------------------------------------
/osafe_images/base_plate.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
46 | Svg Vector Icons : http://www.onlinewebfonts.com/icon
48 |
49 |
107 |
--------------------------------------------------------------------------------
/osafe_images/cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/cancel.png
--------------------------------------------------------------------------------
/osafe_images/change_branch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/osafe_images/civil-engineering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/civil-engineering.png
--------------------------------------------------------------------------------
/osafe_images/civiltools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/civiltools.png
--------------------------------------------------------------------------------
/osafe_images/draw_strip.svg:
--------------------------------------------------------------------------------
1 |
2 |
15 |
17 |
20 |
24 |
28 |
29 |
32 |
36 |
40 |
41 |
44 |
48 |
52 |
53 |
56 |
60 |
64 |
65 |
68 |
72 |
76 |
77 |
88 |
99 |
110 |
111 |
131 |
136 |
140 |
141 |
--------------------------------------------------------------------------------
/osafe_images/dxf.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Svg Vector Icons : http://www.onlinewebfonts.com/icon
6 |
7 |
--------------------------------------------------------------------------------
/osafe_images/etabs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/etabs.png
--------------------------------------------------------------------------------
/osafe_images/explode.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
14 |
17 |
20 |
22 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/osafe_images/export.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
19 |
20 |
25 |
35 |
--------------------------------------------------------------------------------
/osafe_images/f2k.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
65 |
67 |
69 |
71 |
73 |
75 |
77 |
79 |
81 |
83 |
85 |
87 |
89 |
91 | F2K
101 |
--------------------------------------------------------------------------------
/osafe_images/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/help.png
--------------------------------------------------------------------------------
/osafe_images/import.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
53 | Svg Vector Icons : http://www.onlinewebfonts.com/icon
55 |
61 |
62 |
--------------------------------------------------------------------------------
/osafe_images/opening.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
34 |
39 |
43 |
47 |
48 |
--------------------------------------------------------------------------------
/osafe_images/png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/png.png
--------------------------------------------------------------------------------
/osafe_images/rectangle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/osafe_images/refresh.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
70 | Svg Vector Icons : http://www.onlinewebfonts.com/icon
72 |
79 |
80 |
--------------------------------------------------------------------------------
/osafe_images/safe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/safe.png
--------------------------------------------------------------------------------
/osafe_images/segment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/segment.png
--------------------------------------------------------------------------------
/osafe_images/tick.svg:
--------------------------------------------------------------------------------
1 |
2 | image/svg+xml
--------------------------------------------------------------------------------
/osafe_images/trapozeidal.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
34 |
38 |
39 |
--------------------------------------------------------------------------------
/osafe_images/update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/update.png
--------------------------------------------------------------------------------
/osafe_images/update.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
36 |
40 |
44 |
48 |
52 |
56 |
60 |
62 |
63 |
65 |
66 |
68 |
69 |
71 |
72 |
74 |
75 |
77 |
78 |
80 |
81 |
83 |
84 |
86 |
87 |
89 |
90 |
92 |
93 |
95 |
96 |
98 |
99 |
101 |
102 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/osafe_images/wireframe.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Svg Vector Icons : http://www.onlinewebfonts.com/icon
6 |
7 |
--------------------------------------------------------------------------------
/osafe_images/word.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/word.png
--------------------------------------------------------------------------------
/osafe_images/xlsx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_images/xlsx.png
--------------------------------------------------------------------------------
/osafe_import_export/templates/punch_default.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/osafe_import_export/templates/punch_default.docx
--------------------------------------------------------------------------------
/osafe_objects/beam.py:
--------------------------------------------------------------------------------
1 | import FreeCAD
2 | import Draft
3 | from osafe_funcs import osafe_funcs
4 |
5 |
6 | def make_beam(p1, p2):
7 | obj = Draft.make_line(p1, p2)
8 | obj.addProperty("App::PropertyString", "type").type = 'Beam'
9 | if FreeCAD.GuiUp:
10 | osafe_funcs.format_view_object(
11 | obj=obj,
12 | shape_color_entity="beam_shape_color",
13 | line_width_entity="beam_line_width",
14 | transparency_entity="beam_transparency",
15 | display_mode_entity="beam_display_mode",
16 | line_color_entity="beam_line_color",
17 | )
18 | obj.ViewObject.PointSize = 4
19 | FreeCAD.ActiveDocument.recompute()
20 | return obj
21 |
--------------------------------------------------------------------------------
/osafe_objects/colorbar.py:
--------------------------------------------------------------------------------
1 | from PySide2.QtCore import *
2 | from PySide2.QtGui import *
3 | from PySide2.QtWidgets import *
4 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
5 | import matplotlib.pyplot as plt
6 | import matplotlib as mpl
7 | import numpy as np
8 |
9 |
10 | class ColorMap(QWidget):
11 | def __init__(self, minv, maxv, parent=None):
12 | self.max = maxv
13 | self.min = minv
14 | super(ColorMap, self).__init__(parent)
15 | self.figure = plt.figure()
16 | self.canvas = FigureCanvas(self.figure)
17 |
18 | self.draw_colormap()
19 |
20 | # set the layout
21 | layout = QVBoxLayout()
22 | layout.addWidget(self.canvas)
23 | self.setLayout(layout)
24 |
25 | def draw_colormap(self):
26 | # axes
27 | ax = self.figure.add_axes([0.05, 0.10, 0.2, 0.8])
28 | cmap = mpl.cm.jet
29 | norm = mpl.colors.Normalize(vmin=self.min, vmax=self.max)
30 | ticks_cm = np.linspace(self.min, self.max, 10, endpoint=True)
31 | cb1 = mpl.colorbar.ColorbarBase(ax, cmap=cmap,
32 | norm=norm,
33 | ticks=ticks_cm,
34 | orientation='vertical')
35 | # label_cm = 'punch ratio'
36 | # cb1.set_label(label=label_cm,weight='bold')
37 | cb1.ax.tick_params(labelsize=8)
38 | self.canvas.draw()
39 |
--------------------------------------------------------------------------------
/osafe_objects/f2k_object.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 | from pathlib import Path
3 |
4 | import FreeCAD
5 |
6 |
7 | class SafeF2k:
8 | def __init__(self, obj):
9 | self.set_properties(obj)
10 |
11 | def set_properties(self, obj):
12 | self.Type = "f2k"
13 | obj.Proxy = self
14 |
15 | if not hasattr(obj, "input"):
16 | obj.addProperty(
17 | "App::PropertyFile",
18 | "input",
19 | "Safe",
20 | )
21 | if not hasattr(obj, "input_str"):
22 | obj.addProperty(
23 | "App::PropertyString",
24 | "input_str",
25 | "Safe",
26 | ).input_str=''
27 | if not hasattr(obj, "output"):
28 | obj.addProperty(
29 | "App::PropertyFile",
30 | "output",
31 | "Safe",
32 | )
33 | obj.setEditorMode('output', 1)
34 | obj.setEditorMode('input_str', 2)
35 |
36 | def execute(self, obj):
37 | input_ = obj.input
38 | obj.input = input_.replace('/', '\\')
39 | output = obj.output
40 | obj.output = output.replace('/', '\\')
41 | try:
42 | if Path(obj.input).exists():
43 | with open(obj.input) as f:
44 | obj.input_str = f.read()
45 | except:
46 | pass
47 |
48 | def onDocumentRestored(self, obj):
49 | self.set_properties(obj)
50 |
51 | class ViewProviderF2k:
52 | def __init__(self, vobj):
53 | vobj.Proxy = self
54 |
55 | def getIcon(self):
56 | return str(Path(__file__).parent.parent / "osafe_images" / "f2k.svg")
57 |
58 | def __getstate__(self):
59 | return None
60 |
61 | def __setstate__(self, state):
62 | return None
63 |
64 | def make_safe_f2k(
65 | input : str='',
66 | output : Union[str, None] = None,
67 | ):
68 | obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "Safe")
69 | SafeF2k(obj)
70 | obj.input = input
71 | if output is not None:
72 | obj.output = output
73 | if FreeCAD.GuiUp:
74 | ViewProviderF2k(obj.ViewObject)
75 | FreeCAD.ActiveDocument.recompute()
76 | return obj
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/osafe_objects/foundation.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | from typing import Union
3 |
4 | import FreeCAD
5 | import FreeCADGui
6 | import Part
7 |
8 |
9 | class Foundation:
10 | def __init__(self, obj):
11 | self.set_properties(obj)
12 |
13 | def set_properties(self, obj):
14 | self.Type = "Foundation"
15 | obj.Proxy = self
16 |
17 | if not hasattr(obj, "fc"):
18 | obj.addProperty(
19 | "App::PropertyPressure",
20 | "fc",
21 | "Concrete",
22 | )
23 |
24 | if not hasattr(obj, "height"):
25 | obj.addProperty(
26 | "App::PropertyLength",
27 | "height",
28 | "Foundation",
29 | )
30 |
31 | if not hasattr(obj, "cover"):
32 | obj.addProperty(
33 | "App::PropertyLength",
34 | "cover",
35 | "Foundation",
36 | )
37 |
38 | if not hasattr(obj, "d"):
39 | obj.addProperty(
40 | "App::PropertyLength",
41 | "d",
42 | "Foundation",
43 | )
44 |
45 | if not hasattr(obj, "plan"):
46 | obj.addProperty(
47 | "Part::PropertyPartShape",
48 | "plan",
49 | "Foundation",
50 | )
51 |
52 | obj.setEditorMode("d", 2)
53 |
54 | def onDocumentRestored(self, obj):
55 | self.set_properties(obj)
56 |
57 | def execute(self, obj):
58 | obj.d = obj.height - obj.cover
59 | sh = obj.plan.extrude(FreeCAD.Vector(0, 0, -(obj.d.Value)))
60 | obj.Shape = sh
61 |
62 |
63 | class ViewProviderFoundation:
64 |
65 | def __init__(self, vobj):
66 |
67 | vobj.Proxy = self
68 | vobj.Transparency = 40
69 | vobj.DisplayMode = "Shaded"
70 |
71 |
72 | def attach(self, vobj):
73 | self.ViewObject = vobj
74 | self.Object = vobj.Object
75 |
76 | def getIcon(self):
77 | return str(Path(__file__).parent.parent / "osafe_images" / "foundation.png")
78 |
79 | def __getstate__(self):
80 | return None
81 |
82 | def __setstate__(self, state):
83 | return None
84 |
85 |
86 |
87 | def make_foundation(
88 | base: Part.Shape = None,
89 | height: Union[float, str] = 1000,
90 | cover: Union[float, str] = 75,
91 | fc: Union[float, str] = 25
92 | ):
93 | if not base:
94 | base = FreeCADGui.Selection.getSelection()[0].Shape
95 |
96 | obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Foundation")
97 | Foundation(obj)
98 | ViewProviderFoundation(obj.ViewObject)
99 | obj.plan = base
100 | obj.height = height
101 | obj.cover = cover
102 | obj.fc = f"{fc} MPa"
103 |
104 | FreeCAD.ActiveDocument.recompute()
105 |
106 | return obj
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/osafe_objects/opening.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | import Part
3 | import FreeCAD
4 | import Sketcher
5 | import ArchComponent
6 |
7 | try:
8 | from osafe_funcs import osafe_funcs
9 | except:
10 | import osafe_funcs
11 |
12 |
13 | def make_opening(points, height=4000, doc=None):
14 | z = points[0].z
15 | if doc is None:
16 | doc = FreeCAD.ActiveDocument
17 | obj = doc.addObject("Part::FeaturePython", "Opening")
18 | Opening(obj)
19 | sketch = doc.addObject('Sketcher::SketchObject', 'sketch')
20 | sketch.Placement.Base.z = z
21 | points_xy = osafe_funcs.sort_vertex([[p.x, p.y] for p in points])
22 | points_vec = [FreeCAD.Vector(p[0], p[1], 0) for p in points_xy]
23 | points = points_vec + [points_vec[0]]
24 | sketch_lines = []
25 | for p1, p2 in zip(points[:-1], points[1:]):
26 | sketch_lines.append(sketch.addGeometry(Part.LineSegment(p1, p2)))
27 | for l1, l2 in zip(sketch_lines[:-1], sketch_lines[1:]):
28 | sketch.addConstraint(Sketcher.Constraint('Coincident', l1, 2, l2, 1))
29 | sketch.addConstraint(Sketcher.Constraint('Coincident', sketch_lines[-1], 2, sketch_lines[0], 1))
30 | obj.Base = sketch
31 | # sketch.ViewObject.Visibility = False
32 | obj.height = height
33 |
34 | if FreeCAD.GuiUp:
35 | _ViewProviderOpening(obj.ViewObject)
36 | obj.ViewObject.Visibility = False
37 | FreeCAD.ActiveDocument.recompute()
38 | return obj
39 |
40 |
41 | class Opening(ArchComponent.Component):
42 | def __init__(self, obj):
43 | super().__init__(obj)
44 | obj.IfcType = "Opening Element"
45 | self.set_properties(obj)
46 |
47 | def set_properties(self, obj):
48 | obj.Proxy = self
49 | if not hasattr(obj, "plan"):
50 | obj.addProperty(
51 | "Part::PropertyPartShape",
52 | "plan",
53 | "opening",
54 | )
55 | # if not hasattr(obj, "solid"):
56 | # obj.addProperty(
57 | # "Part::PropertyPartShape",
58 | # "solid",
59 | # "opening",
60 | # )
61 | if not hasattr(obj, "height"):
62 | obj.addProperty(
63 | "App::PropertyLength",
64 | "height",
65 | "Base",
66 | )
67 |
68 | def onDocumentRestored(self, obj):
69 | super().onDocumentRestored(obj)
70 | self.set_properties(obj)
71 |
72 | def execute(self, obj):
73 | if hasattr(obj, "Base") and obj.Base:
74 | wire = obj.Base.Shape.Wires[0]
75 | obj.plan = Part.Face(wire)
76 | # points = osafe_funcs.get_sort_points(
77 | # wire.Edges,
78 | # sort_edges=True,
79 | # )
80 | # lines = []
81 | # for p1, p2 in zip(points[:-2], points[2:]):
82 | # lines.append(Part.makeLine(p1, p2))
83 |
84 | shape = obj.plan.extrude(FreeCAD.Vector(0, 0, -obj.height.Value))
85 | # obj.Shape = Part.makeCompound([shape] + lines)
86 | obj.Shape = shape
87 |
88 |
89 | class _ViewProviderOpening:
90 | def __init__(self, vobj):
91 | vobj.Proxy = self
92 | vobj.Transparency = 70
93 | vobj.ShapeColor = (0.00,1.00,1.00)
94 | vobj.DisplayMode = "Shaded"
95 |
96 | def attach(self, vobj):
97 | self.ViewObject = vobj
98 | self.Object = vobj.Object
99 |
100 | def claimChildren(self):
101 | children = [self.Object.Base]
102 | return children
103 |
104 | def onDelete(self, vobj, subelements):
105 | name = None
106 | if vobj.Object.Base:
107 | name = vobj.Object.Base.Name
108 | FreeCAD.ActiveDocument.removeObject(vobj.Object.Name)
109 | if name is not None:
110 | FreeCAD.ActiveDocument.removeObject(name)
111 |
112 | def getIcon(self):
113 | return str(Path(__file__).parent.parent / "osafe_images" / "opening.svg")
114 |
115 | def __getstate__(self):
116 | return None
117 |
118 | def __setstate__(self, state):
119 | return None
120 |
121 |
122 | if __name__ == "__main__":
123 | x1 = 10
124 | x2 = 2500
125 | y1 = 7
126 | y2 = 1700
127 | p1=FreeCAD.Vector(x1, y1, 0)
128 | p2=FreeCAD.Vector(x2, y1, 0)
129 | p3=FreeCAD.Vector(x2, y2, 0)
130 | p4=FreeCAD.Vector(x1, y2, 0)
131 | points = [p1, p2, p3, p4]
132 | make_opening(
133 | points=points,
134 | # height = 3,
135 | )
136 |
--------------------------------------------------------------------------------
/osafe_objects/slab.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | import Part
3 | import FreeCAD
4 | import Draft
5 | # import Sketcher
6 | import ArchComponent
7 |
8 | from osafe_funcs import osafe_funcs
9 |
10 |
11 | def make_slab(
12 | base,
13 | height=1000,
14 | ks = None,
15 | fc = None,
16 | ):
17 | doc = FreeCAD.ActiveDocument
18 | obj = doc.addObject("Part::FeaturePython", "Slab")
19 | Slab(obj)
20 | if isinstance(base, Part.Shape):
21 | if len(base.Wires) == 1:
22 | points = osafe_funcs.get_sort_points(base.Edges)
23 | base = Draft.make_wire(points, closed=True)
24 | else:
25 | base_obj = doc.addObject("Part::FeaturePython", "Base")
26 | base_obj.Shape = base
27 | base = base_obj
28 | obj.Base = base
29 | obj.height = height
30 | if ks is not None:
31 | obj.ks = ks
32 | if fc is not None:
33 | obj.fc = fc
34 | if FreeCAD.GuiUp:
35 | ViewProviderSlab(obj.ViewObject)
36 | FreeCAD.ActiveDocument.recompute()
37 | return obj
38 |
39 |
40 | class Slab(ArchComponent.Component):
41 | def __init__(self, obj):
42 | super().__init__(obj)
43 | obj.IfcType = "Footing"
44 | self.set_properties(obj)
45 |
46 | def set_properties(self, obj):
47 | obj.Proxy = self
48 | self.Type = "Slab"
49 | if not hasattr(obj, "height"):
50 | obj.addProperty(
51 | "App::PropertyLength",
52 | "height",
53 | "Base",
54 | )
55 | if not hasattr(obj, "ks"):
56 | obj.addProperty(
57 | "App::PropertyFloat",
58 | "ks",
59 | "Soil",
60 | )
61 | if not hasattr(obj, "fc"):
62 | obj.addProperty(
63 | "App::PropertyPressure",
64 | "fc",
65 | "Concrete",
66 | )
67 |
68 |
69 | def onDocumentRestored(self, obj):
70 | super().onDocumentRestored(obj)
71 | self.set_properties(obj)
72 |
73 | def execute(self, obj):
74 | if hasattr(obj, "Base") and obj.Base:
75 | obj.Shape = obj.Base.Shape.extrude(FreeCAD.Vector(0, 0, -obj.height.Value))
76 |
77 |
78 | class ViewProviderSlab:
79 | def __init__(self, vobj):
80 | vobj.Proxy = self
81 | vobj.DisplayMode = "Shaded"
82 |
83 | def attach(self, vobj):
84 | self.ViewObject = vobj
85 | self.Object = vobj.Object
86 |
87 | def claimChildren(self):
88 | children = [self.Object.Base]
89 | return children
90 |
91 | def onDelete(self, vobj, subelements):
92 | name = None
93 | if vobj.Object.Base:
94 | name = vobj.Object.Base.Name
95 | FreeCAD.ActiveDocument.removeObject(vobj.Object.Name)
96 | if name is not None:
97 | FreeCAD.ActiveDocument.removeObject(name)
98 |
99 | def getIcon(self):
100 | return str(Path(__file__).parent.parent / "osafe_images" / "slab.svg")
101 |
102 | def __getstate__(self):
103 | return None
104 |
105 | def __setstate__(self, state):
106 | return None
107 |
108 |
109 | if __name__ == "__main__":
110 | import FreeCADGui as Gui
111 | sel = Gui.Selection.getSelection()
112 | if sel:
113 | wire = sel[0]
114 | else:
115 | x1 = 0
116 | x2 = 2500
117 | y1 = 0
118 | y2 = 1700
119 | p1=FreeCAD.Vector(x1, y1, 0)
120 | p2=FreeCAD.Vector(x2, y1, 0)
121 | p3=FreeCAD.Vector(x2, y2, 0)
122 | p4=FreeCAD.Vector(x1, y2, 0)
123 | points = [p1, p2, p3, p4, p1]
124 | import Draft
125 | wire = Draft.make_wire(points)
126 | FreeCAD.ActiveDocument.recompute()
127 | make_slab(base=wire,
128 | )
129 | make_slab(base=wire.Shape)
130 |
--------------------------------------------------------------------------------
/osafe_py_widgets/base_foundation_panel.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import FreeCAD
4 | import FreeCADGui as Gui
5 | from draftutils.translate import translate
6 |
7 | from PySide2.QtWidgets import QMessageBox
8 |
9 | from osafe_funcs import osafe_funcs
10 | from osafe_py_widgets import resource_rc
11 |
12 | punch_path = Path(__file__).parent.parent
13 |
14 |
15 | class Form:
16 |
17 | def __init__(self):
18 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'base_foundation_panel.ui'))
19 | self.create_connections()
20 |
21 |
22 | def getStandardButtons(self):
23 | return 0
24 |
25 | def create_connections(self):
26 | self.form.create_pushbutton.clicked.connect(self.create)
27 | self.form.cancel_pushbutton.clicked.connect(self.accept)
28 |
29 | def create(self):
30 | north_dist = self.form.north_distance.value() * 10 if self.form.north_checkbox.isChecked() else None
31 | south_dist = self.form.south_distance.value() * 10 if self.form.south_checkbox.isChecked() else None
32 | east_dist = self.form.east_distance.value() * 10 if self.form.east_checkbox.isChecked() else None
33 | west_dist = self.form.west_distance.value() * 10 if self.form.west_checkbox.isChecked() else None
34 | x_stirp_name = self.form.x_strip_name.currentText()
35 | y_stirp_name = self.form.y_strip_name.currentText()
36 | width = self.form.width_spinbox.value() * 10
37 | height = self.form.height_spinbox.value() * 10
38 | soil_modulus = self.form.soil_modulus.value()
39 | angle = self.form.angle_spinbox.value()
40 | selection = self.form.selection_checkbox.isChecked()
41 | doc = FreeCAD.ActiveDocument
42 | beams = []
43 | sel = []
44 | if selection:
45 | sel = Gui.Selection.getSelection()
46 | for o in sel:
47 | if (
48 | hasattr(o, "type") and
49 | o.type == 'Beam'
50 | ):
51 | beams.append(o)
52 | else:
53 | for o in doc.Objects:
54 | if (
55 | hasattr(o, "type") and
56 | o.type == 'Beam'
57 | ):
58 | beams.append(o)
59 |
60 | if len(beams) == 0:
61 | if len(sel) > 0:
62 | message = "There is No Beams in selected objects."
63 | else:
64 | message = "There is No Beams in Model."
65 | QMessageBox.warning(None, "Beams", message)
66 | return
67 | if len(sel) == 0: # Check for beams that now are in base foundations
68 | used_beam = osafe_funcs.get_beams_in_doc_that_belogns_to_base_foundations(doc)
69 | current_beam = [beam.Name for beam in beams]
70 | new_beams = set(current_beam).difference(used_beam)
71 | if len(new_beams) == 0:
72 | message = "There is No Remained Beams in Model."
73 | QMessageBox.warning(None, "Beams", message)
74 | return
75 | beams = [doc.getObjectsByLabel(name)[0] for name in new_beams]
76 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Create Base Foundations"))
77 | osafe_funcs.make_automatic_base_foundation(beams, width, north_dist, south_dist,
78 | east_dist, west_dist, x_stirp_name, y_stirp_name, angle, height, soil_modulus)
79 | FreeCAD.ActiveDocument.commitTransaction()
80 | Gui.Selection.clearSelection()
81 | Gui.Control.closeDialog()
82 |
83 | def accept(self):
84 | Gui.Control.closeDialog()
85 |
--------------------------------------------------------------------------------
/osafe_py_widgets/change_branch.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from PySide2.QtWidgets import QMessageBox
4 | import FreeCADGui as Gui
5 | import git
6 |
7 | civil_path = Path(__file__).parent
8 |
9 |
10 | class Form:
11 |
12 | def __init__(self,
13 | git_url : str = "https://github.com/ebrahimraeyat/Civil.git"):
14 | self.git_url = git_url
15 | self.form = Gui.PySideUic.loadUi(str(civil_path / 'Resources' / 'ui' / 'change_branch.ui'))
16 | # self.fill_branches()
17 |
18 | # def fill_branches(self):
19 | # repo = git.Repo(civil_path)
20 | # branch_names = [branch.name for branch in repo.branches]
21 | # if branch_names:
22 | # self.form.branch_list.addItems(branch_names)
23 |
24 |
25 | def accept(self):
26 | g = git.cmd.Git(civil_path)
27 | branch = self.form.branch_list.currentItem().text()
28 | if not branch:
29 | return
30 | succeed = self.checkout(g, branch)
31 | if not succeed:
32 | if not internet():
33 | msg = "You are not connected to the Internet, please check your internet connection."
34 | QMessageBox.warning(None, 'update', str(msg))
35 | return
36 | QMessageBox.information(
37 | None,
38 | "Download",
39 | "Download takes some minutes, please be patient.",
40 | )
41 | g.execute(f'git clone --branch {branch} --depth 1 {self.git_url}')
42 | self.checkout(g, branch)
43 | Gui.Control.closeDialog()
44 |
45 | def checkout(self, g, branch):
46 | try:
47 | g.execute(f'git checkout {branch}')
48 | msg = f'You have successfully moved to {branch}'
49 | QMessageBox.information(None, 'Change Branch', str(msg))
50 | return True
51 | except:
52 | return False
53 |
54 |
55 | def internet(host="8.8.8.8", port=53, timeout=3):
56 | import socket
57 | try:
58 | socket.setdefaulttimeout(timeout)
59 | socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
60 | return True
61 | except Exception as ex:
62 | # print(ex.message)
63 | return False
--------------------------------------------------------------------------------
/osafe_py_widgets/draw_automatic_rebars.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from PySide2.QtWidgets import QMessageBox
4 |
5 | import FreeCAD
6 | import FreeCADGui as Gui
7 | from draftutils.translate import translate
8 |
9 |
10 | from osafe_py_widgets import resource_rc
11 |
12 | punch_path = Path(__file__).parent.parent
13 |
14 |
15 | class Form:
16 |
17 | def __init__(self):
18 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'draw_automatic_rebars.ui'))
19 | self.create_connections()
20 | # if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OSAFE").GetBool("osafe_split_strips", False):
21 | # self.form.split.setChecked(True)
22 | # self.split_clicked(True)
23 | # tol = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OSAFE").GetFloat("osafe_split_strips_tolerance", .001)
24 | # self.form.tolerance.setValue(tol)
25 |
26 | def create_connections(self):
27 | self.form.create_pushbutton.clicked.connect(self.create)
28 | self.form.cancel_pushbutton.clicked.connect(self.accept)
29 | self.form.help.clicked.connect(self.show_help)
30 |
31 | def create(self):
32 | doc = FreeCAD.ActiveDocument
33 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Create Automatic Rebars"))
34 | rebars = []
35 | for obj in doc.Objects:
36 | if (
37 | isinstance(obj, FreeCAD.DocumentObjectGroup) and
38 | 'rebars' in obj.Label.lower()
39 | ):
40 | rebars.append(obj)
41 | if rebars and QMessageBox.question(
42 | None,
43 | 'Remove Rebars',
44 | 'There is rebars exists in Model, Do you want to remove those?',
45 | ) == QMessageBox.Yes:
46 | for rebar in rebars:
47 | for o in rebar.Group:
48 | FreeCAD.ActiveDocument.removeObject(o.Name)
49 | FreeCAD.ActiveDocument.removeObject(rebar.Name)
50 |
51 | from osafe_objects import osafe_rebar
52 | top_rebar_diameter = int(self.form.top_rebar_diameter_combobox.currentText())
53 | bot_rebar_diameter = int(self.form.bot_rebar_diameter_combobox.currentText())
54 | stirrup_diameter = int(self.form.stirrup_rebar_diameter_combobox.currentText())
55 | min_ratio_of_rebars = .0018 if self.form.impose_minimum_checkbox.isChecked() else 0
56 | osafe_rebar.make_rebars(
57 | top_rebar_diameter=top_rebar_diameter,
58 | bot_rebar_diameter=bot_rebar_diameter,
59 | stirrup_diameter=stirrup_diameter,
60 | min_ratio_of_rebars=min_ratio_of_rebars
61 | )
62 | FreeCAD.ActiveDocument.recompute()
63 | FreeCAD.ActiveDocument.commitTransaction()
64 | self.accept()
65 |
66 | def show_help(self):
67 | from freecad_funcs import show_help
68 | show_help('make_auto_rebars.html', 'OSAFE')
69 |
70 | def accept(self):
71 | Gui.Control.closeDialog()
72 |
73 | def getStandardButtons(self):
74 | return 0
75 |
--------------------------------------------------------------------------------
/osafe_py_widgets/draw_automatic_strip.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from PySide2.QtWidgets import QMessageBox
4 |
5 | import FreeCAD
6 | import FreeCADGui as Gui
7 | from draftutils.translate import translate
8 |
9 |
10 | from osafe_py_widgets import resource_rc
11 |
12 | punch_path = Path(__file__).parent.parent
13 |
14 |
15 | class Form:
16 |
17 | def __init__(self):
18 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'draw_automatic_strip.ui'))
19 | self.create_connections()
20 | if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OSAFE").GetBool("osafe_split_strips", False):
21 | self.form.split.setChecked(True)
22 | self.split_clicked(True)
23 | tol = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OSAFE").GetFloat("osafe_split_strips_tolerance", .001)
24 | self.form.tolerance.setValue(tol)
25 | self.set_foundation_type()
26 |
27 | def set_foundation_type(self):
28 | doc = FreeCAD.ActiveDocument
29 | if doc is None:
30 | return
31 | if hasattr(doc, "Foundation"):
32 | if doc.Foundation.foundation_type == "Mat":
33 | self.uncheck_strip()
34 |
35 | def create_connections(self):
36 | self.form.create_pushbutton.clicked.connect(self.create)
37 | self.form.cancel_pushbutton.clicked.connect(self.accept)
38 | self.form.mat_foundation.clicked.connect(self.uncheck_strip)
39 | self.form.strip_foundation.clicked.connect(self.uncheck_mat)
40 | self.form.help.clicked.connect(self.show_help)
41 | self.form.split.clicked.connect(self.split_clicked)
42 |
43 | def split_clicked(self, checked):
44 | self.form.tol_label.setEnabled(checked)
45 | self.form.tolerance.setEnabled(checked)
46 |
47 | def uncheck_strip(self):
48 | self.form.mat_foundation.setChecked(True)
49 | self.form.strip_foundation.setChecked(False)
50 |
51 | def uncheck_mat(self):
52 | self.form.mat_foundation.setChecked(False)
53 | self.form.strip_foundation.setChecked(True)
54 |
55 | def create(self):
56 | doc = FreeCAD.ActiveDocument
57 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Create Automatic Strips"))
58 | strips = []
59 | for obj in doc.Objects:
60 | if (
61 | isinstance(obj, FreeCAD.DocumentObjectGroup) and
62 | 'strips' in obj.Label
63 | ):
64 | strips.append(obj)
65 | if strips and QMessageBox.question(
66 | None,
67 | 'Remove Strips',
68 | 'There is ' + ' and '.join([s.Label for s in strips]) + ' exists in Model, Do you want to remove those?',
69 | ) == QMessageBox.Yes:
70 | for strip in strips:
71 | for o in strip.Group:
72 | FreeCAD.ActiveDocument.removeObject(o.Base.Name)
73 | FreeCAD.ActiveDocument.removeObject(o.Name)
74 | FreeCAD.ActiveDocument.removeObject(strip.Name)
75 |
76 | from osafe_funcs import osafe_funcs
77 | if self.form.mat_foundation.isChecked():
78 | draw_x = self.form.x_strips.isChecked()
79 | draw_y = self.form.y_strips.isChecked()
80 | x_width = self.form.x_width.value()
81 | y_width = self.form.y_width.value()
82 | x_layer_name = self.form.x_layer_name.currentText()
83 | y_layer_name = self.form.y_layer_name.currentText()
84 | equal = self.form.equal.isChecked()
85 | consider_openings = self.form.consider_openings.isChecked()
86 | osafe_funcs.draw_strip_automatically_in_mat_foundation(
87 | # foundation=self.foundation,
88 | x_width=x_width * 10,
89 | y_width=y_width * 10,
90 | x_layer_name=x_layer_name,
91 | y_layer_name=y_layer_name,
92 | draw_x=draw_x,
93 | draw_y=draw_y,
94 | equal=equal,
95 | consider_openings=consider_openings,
96 | )
97 | else:
98 | split = self.form.split.isChecked()
99 | tol = self.form.tolerance.value()
100 | osafe_funcs.draw_strip_automatically_in_strip_foundation(split=split, tolerance=tol)
101 | FreeCAD.ActiveDocument.commitTransaction()
102 | self.accept()
103 | Gui.Selection.clearSelection()
104 |
105 | def show_help(self):
106 | from freecad_funcs import show_help
107 | show_help('make_auto_strip.html', 'OSAFE')
108 |
109 | def accept(self):
110 | Gui.Control.closeDialog()
111 |
112 | def getStandardButtons(self):
113 | return 0
114 |
--------------------------------------------------------------------------------
/osafe_py_widgets/explode_foundation.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | from PySide2 import QtCore
3 | from PySide2.QtWidgets import QMessageBox
4 | import FreeCAD
5 |
6 | import FreeCADGui as Gui
7 |
8 | from draftutils.translate import translate
9 | from osafe_funcs import osafe_funcs
10 |
11 | from osafe_objects.rectangular_slab import make_rectangular_slab_from_base_foundation
12 | from osafe_objects.slab import make_slab
13 |
14 |
15 | class ExplodeFoundation():
16 | """Gui command for the Explode Foundation to rectangular slab objects."""
17 |
18 |
19 | def GetResources(self):
20 | menu_text = QtCore.QT_TRANSLATE_NOOP(
21 | "civil_explode_foundation",
22 | "Explode Foundation")
23 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
24 | "civil_explode_foundation",
25 | "Explode Foundation")
26 | path = str(
27 | Path(__file__).parent.parent / "osafe_images" / "explode_foundation.svg"
28 | )
29 | return {'Pixmap': path,
30 | 'MenuText': menu_text,
31 | 'ToolTip': tool_tip}
32 |
33 | def Activated(self):
34 | """
35 | Execute when the command is called.
36 | """
37 |
38 | # The command to run is built as a series of text strings
39 | # to be committed through the `draftutils.todo.ToDo` class.
40 | sel = Gui.Selection.getSelection()
41 | if not sel:
42 | show_warning()
43 | return
44 | foun = None
45 | for o in sel:
46 | if hasattr(o, "IfcType") and o.IfcType == 'Footing':
47 | foun = o
48 | break
49 | if foun is None:
50 | show_warning()
51 | return
52 | if not foun.base_foundations:
53 | return
54 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Explode Foundation"))
55 | if foun.continuous_layer != 'AB':
56 | foun.continuous_layer = 'AB'
57 | FreeCAD.ActiveDocument.recompute()
58 | slabs = []
59 | if foun.foundation_type == 'Strip':
60 | for bf in foun.base_foundations:
61 | slab = make_rectangular_slab_from_base_foundation(bf, plan='Auto')
62 | slabs.append(slab)
63 | elif foun.foundation_type == 'Mat':
64 | height = foun.height
65 | if foun.split:
66 | solids = foun.Shape.Solids
67 | assert len(solids) == 5
68 | p0 = osafe_funcs.get_top_faces(solids[0], fuse=True)
69 | p1 = osafe_funcs.get_top_faces(solids[1], fuse=True)
70 | p2 = osafe_funcs.get_top_faces(solids[2], fuse=True)
71 | p3 = osafe_funcs.get_top_faces(solids[3], fuse=True)
72 | p4 = osafe_funcs.get_top_faces(solids[4], fuse=True)
73 | s0 = make_slab(p0, height=height,fc=foun.fc, ks= 2 * foun.ks)
74 | s1 = make_slab(p1, height=height,fc=foun.fc, ks= 2 * foun.ks)
75 | s2 = make_slab(p2, height=height,fc=foun.fc, ks= 1.5 * foun.ks)
76 | s3 = make_slab(p3, height=height,fc=foun.fc, ks= 1.5 * foun.ks)
77 | s4 = make_slab(p4, height=height,fc=foun.fc, ks= foun.ks)
78 | slabs.extend([s0, s1, s2, s3, s4])
79 | else:
80 | s = make_slab(foun.plan, height=height, fc=foun.fc, ks=foun.ks)
81 | slabs.append(s)
82 | foun_slabs = []
83 | for slab in slabs:
84 | if slab not in foun.Slabs:
85 | foun_slabs.append(slab)
86 | foun_slabs.extend(foun.Slabs)
87 | foun.base_foundations = []
88 | foun.Slabs = foun_slabs
89 | for slab in foun.Slabs:
90 | slab.ViewObject.hide()
91 | FreeCAD.ActiveDocument.recompute()
92 | FreeCAD.ActiveDocument.commitTransaction()
93 |
94 | def IsActive(self):
95 | return not FreeCAD.ActiveDocument is None
96 |
97 | def remove_obj(name: str) -> None:
98 | o = FreeCAD.ActiveDocument.getObject(name)
99 | if hasattr(o, "Base") and o.Base:
100 | remove_obj(o.Base.Name)
101 | FreeCAD.ActiveDocument.removeObject(name)
102 |
103 | def show_warning():
104 | QMessageBox.warning(None, 'Selection', 'Please select the foundation!')
105 |
106 | Gui.addCommand('osafe_explode_foundation', ExplodeFoundation())
107 |
108 | ## @}
109 |
--------------------------------------------------------------------------------
/osafe_py_widgets/explode_seismic_load_patterns.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import FreeCADGui as Gui
4 |
5 | import etabs_obj
6 | from osafe_py_widgets import resource_rc
7 | from PySide2.QtGui import QPixmap
8 |
9 | punch_path = Path(__file__).parent.parent
10 |
11 | class Form:
12 | def __init__(self, parent=None):
13 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'explode_seismic_load_patterns.ui'))
14 | self.etabs = etabs_obj.EtabsModel(backup=False)
15 | self.form.start_button.clicked.connect(self.accept)
16 | # self.form.close_button.clicked.connect(self.reject)
17 |
18 | def accept(self):
19 | ex = self.form.ex.text()
20 | epx = self.form.epx.text()
21 | enx = self.form.enx.text()
22 | ey = self.form.ey.text()
23 | epy = self.form.epy.text()
24 | eny = self.form.eny.text()
25 | equal_names = {
26 | 'XDir' : ex,
27 | 'XDirPlusE' : epx,
28 | 'XDirMinusE' : enx,
29 | 'YDir' : ey,
30 | 'YDirPlusE' : epy,
31 | 'YDirMinusE' : eny,
32 | }
33 | replace_ex = self.form.replace_ex.isChecked()
34 | replace_ey = self.form.replace_ey.isChecked()
35 | drift_prefix = self.form.drift_prefix.text()
36 | drift_suffix = self.form.drift_suffix.text()
37 | pixmap = QPixmap(str(punch_path / 'Resources' / 'icons' / 'tick.svg'))
38 | for ret in self.etabs.database.expand_loads(
39 | equal_names=equal_names,
40 | replace_ex = replace_ex,
41 | replace_ey = replace_ey,
42 | drift_prefix = drift_prefix,
43 | drift_suffix = drift_suffix,
44 | ):
45 | if type(ret) == tuple and len(ret) == 2:
46 | message, number = ret
47 | if type(message) == str and type(number) == int:
48 | self.form.result_label.setText(message)
49 | self.form.progressbar.setValue(number)
50 | if message.startswith('Get'):
51 | if 'case' in message:
52 | self.form.get_loadpat.setPixmap(pixmap)
53 | elif 'load combinations' in message:
54 | if 'Design' in message:
55 | self.form.get_loadcomb.setPixmap(pixmap)
56 | else:
57 | self.form.get_loadcase.setPixmap(pixmap)
58 | elif message.startswith('Apply'):
59 | if 'pattern' in message:
60 | self.form.get_design_loadcomb.setPixmap(pixmap)
61 | elif 'case' in message:
62 | self.form.set_loadpat.setPixmap(pixmap)
63 | elif 'load combinations' in message:
64 | if 'Design' in message:
65 | self.form.set_loadcomb.setPixmap(pixmap)
66 | else:
67 | self.form.set_loadcase.setPixmap(pixmap)
68 | elif 'Finished' in message:
69 | self.form.set_design_loadcomb.setPixmap(pixmap)
70 | elif type(ret) == bool:
71 | if not ret:
72 | self.form.result_label.setText("Error Occurred, process did not finished.")
73 | self.form.start_button.setEnabled(False)
74 | elif type(ret) == str:
75 | self.form.result_label.setText(ret)
76 |
77 |
--------------------------------------------------------------------------------
/osafe_py_widgets/export/export_to_dxf_dialog.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from PySide2.QtWidgets import QMessageBox
4 |
5 | import FreeCAD
6 | import FreeCADGui as Gui
7 |
8 | from osafe_py_widgets import resource_rc
9 |
10 | punch_path = Path(__file__).parent.parent.parent
11 |
12 |
13 | class Form:
14 |
15 | def __init__(self):
16 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'export' / 'export_to_dxf.ui'))
17 | self.fill_filename()
18 | self.create_connections()
19 |
20 | def fill_filename(self):
21 | doc = FreeCAD.ActiveDocument
22 | if doc.FileName:
23 | name = Path(doc.FileName).with_suffix('.dxf')
24 | else:
25 | try:
26 | import etabs_obj
27 | etabs = etabs_obj.EtabsModel(backup=False)
28 | name = etabs.get_filename().with_suffix('.dxf')
29 | except:
30 | name = ''
31 | self.form.filename.setText(str(name))
32 |
33 | def create_connections(self):
34 | self.form.browse.clicked.connect(self.browse)
35 | self.form.export_button.clicked.connect(self.export)
36 | self.form.cancel_pushbutton.clicked.connect(self.accept)
37 |
38 | def browse(self):
39 | ext = '.dxf'
40 | from PySide2.QtWidgets import QFileDialog
41 | filters = f"{ext[1:]} (*{ext})"
42 | filename, _ = QFileDialog.getSaveFileName(None, 'select file',
43 | None, filters)
44 | if not filename:
45 | return
46 | if not filename.lower().endswith(ext):
47 | filename += ext
48 | self.form.filename.setText(filename)
49 |
50 | def export(self):
51 | filename = self.form.filename.text()
52 | if not filename:
53 | return
54 | from osafe_import_export import export
55 | ret = export.to_dxf(
56 | filename,
57 | columns=self.form.columns_checkbox.isChecked(),
58 | punches=self.form.punches_checkbox.isChecked(),
59 | )
60 | if ret:
61 | QMessageBox.information(None, 'Successful', f'Model has been exported to {filename}')
62 |
63 | def getStandardButtons(self):
64 | return 0
65 |
66 | def accept(self):
67 | Gui.Control.closeDialog()
68 |
--------------------------------------------------------------------------------
/osafe_py_widgets/export/import_from_dxf_dialog.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 |
4 | import FreeCAD
5 | import FreeCADGui as Gui
6 |
7 | from osafe_py_widgets import resource_rc
8 |
9 | punch_path = Path(__file__).parent.parent.parent
10 |
11 |
12 | class Form:
13 |
14 | def __init__(self):
15 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'import_from_dxf.ui'))
16 | # self.fill_filename()
17 | self.create_connections()
18 |
19 | def fill_filename(self):
20 | doc = FreeCAD.ActiveDocument
21 | name = Path(doc.FileName).with_suffix('.dxf')
22 | self.form.filename.setText(str(name))
23 |
24 | def create_connections(self):
25 | self.form.browse.clicked.connect(self.browse)
26 | self.form.import_button.clicked.connect(self.import_dxf)
27 | self.form.cancel_pushbutton.clicked.connect(self.accept)
28 |
29 | def browse(self):
30 | ext = '.dxf'
31 | from PySide2.QtWidgets import QFileDialog
32 | filters = f"{ext[1:]} (*{ext})"
33 | filename, _ = QFileDialog.getOpenFileName(None, 'select file',
34 | None, filters)
35 | if not filename:
36 | return
37 | if not filename.lower().endswith(ext):
38 | filename += ext
39 | self.form.filename.setText(filename)
40 |
41 | def import_dxf(self):
42 | filename = self.form.filename.text()
43 | if not filename:
44 | return
45 | scale = self.form.scale_box.value()
46 | p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
47 | p.SetFloat("dxfScaling", scale)
48 | p.SetBool("dxfUseLegacyImporter", True)
49 | p.GetBool("dxfGetOriginalColors", True)
50 |
51 | import importDXF
52 | importDXF.readPreferences()
53 | doc = FreeCAD.ActiveDocument
54 | importDXF.getDXFlibs()
55 | gui = FreeCAD.GuiUp
56 | if importDXF.dxfReader:
57 | # groupname = str(Path(filename).name)
58 | # importgroup = doc.addObject("App::DocumentObjectGroup", groupname)
59 | # importgroup.Label = groupname
60 | importDXF.processdxf(doc, filename)
61 | # for l in layers:
62 | # importgroup.addObject(l)
63 | else:
64 | importDXF.errorDXFLib(gui)
65 | self.accept()
66 | if gui:
67 | Gui.SendMsgToActiveView("ViewFit")
68 |
69 | def getStandardButtons(self):
70 | return 0
71 |
72 | def accept(self):
73 | Gui.Control.closeDialog()
74 |
--------------------------------------------------------------------------------
/osafe_py_widgets/force_panel.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from PySide2.QtWidgets import QMessageBox
4 | import FreeCAD
5 | import FreeCADGui as Gui
6 | from draftutils.translate import translate
7 |
8 | from osafe_py_widgets import resource_rc
9 |
10 | punch_path = Path(__file__).parent.parent
11 |
12 |
13 | class ForceTaskPanel:
14 |
15 | def __init__(self):
16 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'force_panel.ui'))
17 | self.foun = FreeCAD.ActiveDocument.Foundation
18 | self.fill_load_cases()
19 | self.create_connections()
20 | self.all_loads = []
21 | self.hide_loads()
22 |
23 | def create_connections(self):
24 | self.form.assign_button.clicked.connect(self.assign_load)
25 | self.form.loadcase.currentIndexChanged.connect(self.hide_loads)
26 |
27 | def fill_load_cases(self):
28 | deads = []
29 | try:
30 | import find_etabs
31 | etabs, _ = find_etabs.find_etabs(run=False, backup=False)
32 | deads = etabs.load_patterns.get_special_load_pattern_names(1)
33 | except:
34 | if hasattr(FreeCAD, 'load_cases'):
35 | deads = FreeCAD.load_cases
36 | self.form.loadcase.addItems(deads)
37 |
38 | def hide_loads(self):
39 | try:
40 | loads = FreeCAD.ActiveDocument.findObjects(Type='Fem::ConstraintForce')
41 | for load in loads:
42 | load.ViewObject.hide()
43 | self.all_loads = [load.Name for load in loads]
44 | except TypeError:
45 | pass
46 |
47 | def assign_load(self):
48 | loadcase = self.form.loadcase.currentText()
49 | if not loadcase:
50 | QMessageBox.warning(None,
51 | 'Dead load case',
52 | 'Please Select Dead loadcase first.',
53 | )
54 | return
55 | load_value = self.form.load_value.value()
56 | version = float('.'.join(FreeCAD.Version()[0:2]))
57 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Apply load on Foundation"))
58 | if version <= 0.19:
59 | Gui.activateWorkbench("FemWorkbench")
60 | Gui.activateWorkbench("OSAFEWorkbench")
61 | loads = FreeCAD.ActiveDocument.findObjects(Type='Fem::ConstraintForce')
62 | all_loads = [load.Name for load in loads]
63 | if loadcase in all_loads:
64 | load = FreeCAD.ActiveDocument.getObject(loadcase)
65 | load.Force = load_value
66 | load.ViewObject.show()
67 | else:
68 | constraint = FreeCAD.ActiveDocument.addObject('Fem::ConstraintForce', loadcase)
69 | constraint.addProperty('App::PropertyString', 'loadcase', 'Base')
70 | constraint.loadcase = loadcase
71 | references_names = []
72 | top_of_foundation = self.foun.Shape.BoundBox.ZMax
73 | for i, face in enumerate(self.foun.Shape.Faces, start=1):
74 | if face.BoundBox.ZMin == top_of_foundation:
75 | references_names.append(f'Face{i}')
76 | constraint.References = [(self.foun, tuple(references_names))]
77 | constraint.Force = load_value
78 | constraint.Reversed = True
79 | FreeCAD.ActiveDocument.recompute()
80 | FreeCAD.ActiveDocument.commitTransaction()
81 |
82 | if __name__ == '__main__':
83 | panel = ForceTaskPanel()
84 |
--------------------------------------------------------------------------------
/osafe_py_widgets/gui_automatic_strip.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 |
4 | from PySide2 import QtCore
5 | from PySide2.QtCore import QT_TRANSLATE_NOOP
6 |
7 | import FreeCAD
8 | import FreeCADGui as Gui
9 |
10 |
11 | class OsafeAutomaticStrip:
12 | """Gui command for the creating stirp automatically in mat foundations."""
13 |
14 | def GetResources(self):
15 | menu_text = QtCore.QT_TRANSLATE_NOOP(
16 | "osafe",
17 | "Auto Strip")
18 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
19 | "osafe",
20 | "Create Strips automatically in mat foundations")
21 | path = str(
22 | Path(__file__).parent.parent / "osafe_images" / "auto_strip.svg"
23 | )
24 | return {'Pixmap': path,
25 | 'MenuText': menu_text,
26 | 'ToolTip': tool_tip}
27 |
28 | def Activated(self):
29 | # def is_foundation_type(obj):
30 | # if hasattr(obj, 'IfcType') and obj.IfcType == 'Footing':
31 | # return True
32 | # return False
33 |
34 | # doc = FreeCAD.ActiveDocument
35 | # sel = Gui.Selection.getSelection()
36 | # foun = None
37 | # if sel and is_foundation_type(sel[0]):
38 | # foun = sel[0]
39 | # if foun is None:
40 | # for o in doc.Objects:
41 | # if is_foundation_type(o):
42 | # foun = o
43 | # break
44 | # if foun is None:
45 | # return
46 | # print('ali')
47 | from osafe_py_widgets import draw_automatic_strip
48 | win = draw_automatic_strip.Form()
49 | Gui.Control.showDialog(win)
50 |
51 | def IsActive(self):
52 | return not FreeCAD.ActiveDocument is None
--------------------------------------------------------------------------------
/osafe_py_widgets/gui_dxf.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 |
4 | from PySide2 import QtCore
5 |
6 | import FreeCAD
7 | import FreeCADGui as Gui
8 |
9 |
10 | class OsafeDxf:
11 | """Gui command for the Create DXF."""
12 |
13 | def GetResources(self):
14 | menu_text = QtCore.QT_TRANSLATE_NOOP(
15 | "OSAFE",
16 | "DXF")
17 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
18 | "OSAFE",
19 | "Export Foundation To DXF")
20 | path = str(
21 | Path(__file__).parent.parent / "osafe_images" / "dxf.svg"
22 | )
23 | return {'Pixmap': path,
24 | 'MenuText': menu_text,
25 | 'ToolTip': tool_tip}
26 |
27 | def Activated(self):
28 | from osafe_py_widgets.export import export_to_dxf_dialog
29 | win = export_to_dxf_dialog.Form()
30 | Gui.Control.showDialog(win)
31 |
32 | def IsActive(self):
33 | return not FreeCAD.ActiveDocument is None
34 |
35 |
36 | class OsafeImportDxf:
37 | """Gui command for import DXF files."""
38 |
39 | def GetResources(self):
40 | menu_text = QtCore.QT_TRANSLATE_NOOP(
41 | "OSAFE",
42 | "Import DXF")
43 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
44 | "OSAFE",
45 | "Import DXF file into current model")
46 | path = str(
47 | Path(__file__).parent.parent / "osafe_images" / "import_dxf.svg"
48 | )
49 | return {'Pixmap': path,
50 | 'MenuText': menu_text,
51 | 'ToolTip': tool_tip}
52 |
53 | def Activated(self):
54 | from osafe_py_widgets.export import import_from_dxf_dialog
55 | win = import_from_dxf_dialog.Form()
56 | Gui.Control.showDialog(win)
57 |
58 | def IsActive(self):
59 | return not FreeCAD.ActiveDocument is None
--------------------------------------------------------------------------------
/osafe_py_widgets/gui_export_strips.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 |
4 | from PySide2 import QtCore
5 |
6 | import FreeCAD
7 | import FreeCADGui as Gui
8 |
9 |
10 | class OsafeExportStrips:
11 | """Gui command for the Create DXF."""
12 |
13 | def GetResources(self):
14 | menu_text = QtCore.QT_TRANSLATE_NOOP(
15 | "OSAFE",
16 | "Export Strips")
17 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
18 | "OSAFE",
19 | "Export Strips to ETABS or SAFE")
20 | path = str(
21 | Path(__file__).parent.parent / "osafe_images" / "export_strips.svg"
22 | )
23 | return {'Pixmap': path,
24 | 'MenuText': menu_text,
25 | 'ToolTip': tool_tip}
26 |
27 | def Activated(self):
28 | from osafe_py_widgets.export import export_strips_panel
29 | win = export_strips_panel.Form()
30 | Gui.Control.showDialog(win)
31 |
32 | def IsActive(self):
33 | return not FreeCAD.ActiveDocument is None
34 |
35 |
36 | if FreeCAD.GuiUp:
37 | Gui.addCommand('osafe_export_strips',OsafeExportStrips())
--------------------------------------------------------------------------------
/osafe_py_widgets/gui_punch.py:
--------------------------------------------------------------------------------
1 |
2 | from pathlib import Path
3 |
4 | from PySide2 import QtCore
5 | from PySide2.QtCore import QT_TRANSLATE_NOOP
6 |
7 | import FreeCAD
8 | import FreeCADGui as Gui
9 | import Draft
10 | from draftutils.translate import translate
11 |
12 | from osafe_objects.punch import make_punch
13 |
14 |
15 | class Punch:
16 | """Gui command for the Punch."""
17 |
18 | def GetResources(self):
19 | menu_text = QtCore.QT_TRANSLATE_NOOP(
20 | "civil_punch",
21 | "Create punch")
22 | tool_tip = QtCore.QT_TRANSLATE_NOOP(
23 | "civil_punch",
24 | "Create punch")
25 | path = str(
26 | Path(__file__).parent.parent / "osafe_images" / "punch.svg"
27 | )
28 | return {'Pixmap': path,
29 | 'MenuText': menu_text,
30 | 'ToolTip': tool_tip}
31 |
32 | def Activated(self):
33 | def is_foundation_type(obj):
34 | if hasattr(obj, 'Proxy') and hasattr(obj.Proxy, 'Type') and obj.Proxy.Type == 'Foundation':
35 | return True
36 | return False
37 |
38 | doc = FreeCAD.ActiveDocument
39 | sel = Gui.Selection.getSelection()
40 | foun = None
41 | if sel and is_foundation_type(sel[0]):
42 | foun = sel[0]
43 | if foun is None:
44 | for o in doc.Objects:
45 | if is_foundation_type(o):
46 | foun = o
47 | break
48 | if foun is None:
49 | return
50 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Create Punches"))
51 | if hasattr(doc, 'Punches'):
52 | punches = doc.Punches
53 | columns = [punch.column.Name for punch in punches.Group]
54 | else:
55 | punches = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","Punches")
56 | columns = []
57 | for o in doc.Objects:
58 | if hasattr(o, 'IfcType') and \
59 | o.IfcType == 'Column' and \
60 | hasattr(o, 'combos_load') and \
61 | hasattr(o, 'Base'):
62 | if o.Name in columns:
63 | continue
64 | punch = make_punch(
65 | foun,
66 | o,
67 | )
68 | l = punch.Location
69 | pl = FreeCAD.Vector(0, 0, o.Shape.BoundBox.ZMax)
70 | t = '0.0'
71 | text = Draft.make_text([t, l], placement=pl)
72 | punch.Ratio = t
73 | if FreeCAD.GuiUp:
74 | text.ViewObject.FontSize = 200
75 | punch.text = text
76 | punch.id = o.Label
77 | punches.addObject(punch)
78 | FreeCAD.ActiveDocument.recompute()
79 | FreeCAD.ActiveDocument.commitTransaction()
80 |
81 | def IsActive(self):
82 | return not FreeCAD.ActiveDocument is None
--------------------------------------------------------------------------------
/osafe_py_widgets/resource.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | ../osafe_images/tick.svg
4 | ../osafe_images/osafe_rebar.svg
5 | ../osafe_images/auto_strip.svg
6 | ../osafe_images/force.svg
7 | ../osafe_images/wall.svg
8 | ../osafe_images/export_strips.svg
9 | ../osafe_images/foundation.svg
10 | ../osafe_images/base_foundation.svg
11 | ../osafe_images/safe.png
12 | ../osafe_images/refresh.svg
13 | ../osafe_images/import_dxf.svg
14 | ../osafe_images/base_plate.svg
15 | ../osafe_images/import.svg
16 | ../osafe_images/etabs.png
17 | ../osafe_images/help.png
18 | ../osafe_images/strip.svg
19 | ../osafe_images/punch.svg
20 | ../osafe_images/dxf.svg
21 | ../osafe_images/cancel.png
22 |
23 |
24 |
--------------------------------------------------------------------------------
/osafe_py_widgets/wall_panel.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from PySide2 import QtWidgets
4 |
5 | import FreeCAD
6 | import FreeCADGui as Gui
7 | import ArchWall
8 | from draftutils.translate import translate
9 |
10 | from osafe_py_widgets import resource_rc
11 |
12 | punch_path = Path(__file__).parent.parent
13 |
14 |
15 | class WallTaskPanel:
16 |
17 | def __init__(self):
18 | self.form = Gui.PySideUic.loadUi(str(punch_path / 'osafe_widgets' / 'wall_panel.ui'))
19 | self.fill_load_cases()
20 | self.create_connections()
21 | Gui.runCommand('Std_DrawStyle',2)
22 | Gui.runCommand('OSAFE_view_beams',1)
23 | Gui.runCommand('OSAFE_view_basefoundation',0)
24 | Gui.runCommand('OSAFE_view_design_layer_a',0)
25 | Gui.runCommand('OSAFE_view_design_layer_b',0)
26 |
27 | def fill_load_cases(self):
28 | deads = []
29 | try:
30 | import find_etabs
31 | etabs, _ = find_etabs.find_etabs(run=False, backup=False)
32 | deads = etabs.load_patterns.get_special_load_pattern_names(1)
33 | except:
34 | if hasattr(FreeCAD, 'load_cases'):
35 | deads = FreeCAD.load_cases
36 | self.form.loadpat.addItems(deads)
37 |
38 | def create_connections(self):
39 | self.form.create_button.clicked.connect(self.create_wall)
40 |
41 | def create_wall(self):
42 | loadpat = self.form.loadpat.currentText()
43 | if not loadpat:
44 | QtWidgets.QMessageBox.warning(None, "Load Case Name", "Please Enter the name of the Loadcase.")
45 | return
46 | sel = Gui.Selection.getSelection()
47 | if len(sel) == 0:
48 | QtWidgets.QMessageBox.warning(None, "Selection", "Please Select Lines or Wires.")
49 | return
50 |
51 | wires = []
52 | import draftutils.utils as utils
53 | for s in sel:
54 | if utils.get_type(s) == 'Wire':
55 | wires.append(s)
56 | if len(wires) == 0:
57 | QtWidgets.QMessageBox.warning(None, "Selection", "Please Select Lines or Wires.")
58 | return
59 | weight = self.form.weight.value()
60 | height = self.form.height_box.value()
61 | create_blocks = self.form.create_blocks.isChecked()
62 | mat = FreeCAD.ActiveDocument.findObjects(Type='App::MaterialObjectPython')
63 | FreeCAD.ActiveDocument.openTransaction(translate("OSAFE","Create Walls"))
64 | if not mat:
65 | import Arch
66 | mat = Arch.makeMaterial('Bricks')
67 | mat.Color = (0.89, .89, 0.)
68 | else:
69 | mat = mat[0]
70 | for s in wires:
71 | wall = ArchWall.makeWall(baseobj=s,height=height * 1000)
72 | wall.addProperty('App::PropertyInteger', 'weight', 'Wall')
73 | wall.addProperty('App::PropertyString', 'loadpat', 'Wall')
74 | wall.loadpat = loadpat
75 | wall.weight = weight
76 | wall.Base.ViewObject.Visibility = True
77 | wall.Material = mat
78 | wall.Width = 300
79 | if create_blocks:
80 | wall.MakeBlocks = True
81 | wall.BlockHeight = 400
82 | wall.BlockLength = 800
83 | wall.OffsetSecond = 400
84 | wall.Joint = 40
85 | wall.ViewObject.DisplayMode = 'Flat Lines'
86 | wall.ViewObject.LineWidth = 1
87 | else:
88 | wall.ViewObject.DisplayMode = 'Shaded'
89 | wall.ViewObject.Transparency = 60
90 | FreeCAD.ActiveDocument.recompute()
91 | Gui.runCommand('Std_DrawStyle',0)
92 | FreeCAD.ActiveDocument.commitTransaction()
93 |
--------------------------------------------------------------------------------
/osafe_statusbar.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import os
4 | import FreeCAD
5 | from osafe_translate_utils import *
6 |
7 |
8 | # Language path for InitGui.py
9 |
10 |
11 | def getLanguagePath():
12 |
13 | return os.path.join(os.path.dirname(__file__),"translations")
14 |
15 |
16 | # Status bar buttons
17 |
18 |
19 | def setStatusIcons(show=True):
20 |
21 | "shows or hides the BIM icons in the status bar"
22 |
23 | import FreeCADGui
24 | from PySide import QtCore,QtGui
25 |
26 |
27 | def addonMgr():
28 |
29 | mw = FreeCADGui.getMainWindow()
30 | if mw:
31 | st = mw.statusBar()
32 | statuswidget = st.findChild(QtGui.QToolBar,"OSAFEStatusWidget")
33 | if statuswidget:
34 | updatebutton = statuswidget.findChild(QtGui.QPushButton,"UpdateButton")
35 | if updatebutton:
36 | statuswidget.actions()[-1].setVisible(False)
37 | FreeCADGui.runCommand("Std_AddonMgr")
38 |
39 |
40 | class CheckWorker(QtCore.QThread):
41 |
42 | updateAvailable = QtCore.Signal(bool)
43 |
44 | def __init__(self):
45 |
46 | QtCore.QThread.__init__(self)
47 |
48 | def run(self):
49 |
50 | try:
51 | import git
52 | except ImportError:
53 | return
54 | FreeCAD.Console.PrintLog("Checking for available updates of the OSAFE workbench\n")
55 | osafe_dir = os.path.join(FreeCAD.getUserAppDataDir(),"Mod","OSAFE")
56 | etabs_api_dir = os.path.join(FreeCAD.getUserAppDataDir(),"Mod","etabs_api")
57 | for directory in (osafe_dir, etabs_api_dir):
58 | if os.path.exists(directory) and os.path.exists(directory + os.sep + '.git'):
59 | gitrepo = git.Git(directory)
60 | try:
61 | gitrepo.fetch()
62 | if "git pull" in gitrepo.status():
63 | self.updateAvailable.emit(True)
64 | return
65 | except:
66 | # can fail for any number of reasons, ex. not being online
67 | pass
68 | self.updateAvailable.emit(False)
69 |
70 | def checkUpdates():
71 | FreeCAD.osafe_update_checker = CheckWorker()
72 | FreeCAD.osafe_update_checker.updateAvailable.connect(showUpdateButton)
73 | FreeCAD.osafe_update_checker.start()
74 |
75 | def showUpdateButton(avail):
76 | if avail:
77 | FreeCAD.Console.PrintLog("An OSAFE update is available\n")
78 | mw = FreeCADGui.getMainWindow()
79 | if mw:
80 | st = mw.statusBar()
81 | statuswidget = st.findChild(QtGui.QToolBar,"OSAFEStatusWidget")
82 | if statuswidget:
83 | updatebutton = statuswidget.findChild(QtGui.QPushButton,"UpdateButton")
84 | if updatebutton:
85 | # updatebutton.show() # doesn't work for some reason
86 | statuswidget.actions()[-1].setVisible(True)
87 | else:
88 | FreeCAD.Console.PrintLog("No OSAFE update available\n")
89 | if hasattr(FreeCAD,"osafe_update_checker"):
90 | del FreeCAD.osafe_update_checker
91 |
92 |
93 | # main code
94 |
95 | mw = FreeCADGui.getMainWindow()
96 | if mw:
97 | st = mw.statusBar()
98 | statuswidget = st.findChild(QtGui.QToolBar,"OSAFEStatusWidget")
99 | if show:
100 | if statuswidget:
101 | statuswidget.show()
102 | else:
103 | statuswidget = QtGui.QToolBar()
104 | statuswidget.setObjectName("OSAFEStatusWidget")
105 |
106 | # update notifier button (starts hidden)
107 | updatebutton = QtGui.QPushButton()
108 | bwidth = updatebutton.fontMetrics().boundingRect("AAAA").width()
109 | updatebutton.setObjectName("UpdateButton")
110 | updatebutton.setMaximumWidth(bwidth)
111 | updatebutton.setIcon(QtGui.QIcon(os.path.join(os.path.dirname(__file__),"images","update.svg")))
112 | updatebutton.setText("")
113 | updatebutton.setToolTip(translate("osafe","An update to the OSAFE workbench is available. Click here to open the addons manager."))
114 | updatebutton.setFlat(True)
115 | QtCore.QObject.connect(updatebutton,QtCore.SIGNAL("pressed()"),addonMgr)
116 | updatebutton.hide()
117 | statuswidget.addWidget(updatebutton)
118 | st.addPermanentWidget(statuswidget)
119 | QtCore.QTimer.singleShot(2500, checkUpdates) # delay a bit the check for osafe WB update...
120 | else:
121 | if statuswidget:
122 | statuswidget.hide()
123 | else:
124 | # when switching workbenches, the toolbar sometimes "jumps"
125 | # out of the status bar to any other dock area...
126 | statuswidget = mw.findChild(QtGui.QToolBar,"OSAFEStatusWidget")
127 | if statuswidget:
128 | statuswidget.hide()
129 |
130 |
--------------------------------------------------------------------------------
/osafe_translate_utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf8 -*-
2 |
3 | #***************************************************************************
4 | #* *
5 | #* Copyright (c) 2017 Yorik van Havre *
6 | #* *
7 | #* This program is free software; you can redistribute it and/or modify *
8 | #* it under the terms of the GNU Lesser General Public License (LGPL) *
9 | #* as published by the Free Software Foundation; either version 2 of *
10 | #* the License, or (at your option) any later version. *
11 | #* for detail see the LICENCE text file. *
12 | #* *
13 | #* This program is distributed in the hope that it will be useful, *
14 | #* but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 | #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 | #* GNU Library General Public License for more details. *
17 | #* *
18 | #* You should have received a copy of the GNU Library General Public *
19 | #* License along with this program; if not, write to the Free Software *
20 | #* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21 | #* USA *
22 | #* *
23 | #***************************************************************************
24 |
25 | """Locate the translation utils"""
26 |
27 | import FreeCAD
28 |
29 | # dummy function for the QT translator
30 | def QT_TRANSLATE_NOOP(ctx,txt):
31 | return txt
32 |
33 | # use latest available translate function
34 | if hasattr(FreeCAD,"Qt"):
35 | translate = FreeCAD.Qt.translate
36 | else:
37 | from DraftTools import translate
38 |
--------------------------------------------------------------------------------
/osafe_widgets/change_branch.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | QDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 330
10 | 300
11 |
12 |
13 |
14 | Change Branch
15 |
16 |
17 | -
18 |
19 |
20 | Select Branch
21 |
22 |
23 |
24 | -
25 |
26 |
27 | 1
28 |
29 | -
30 |
31 | master
32 |
33 |
34 | -
35 |
36 | develop
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/osafe_widgets/civil_welcome.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 468
10 | 617
11 |
12 |
13 |
14 | Welcome
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 450
22 | 178
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | -
31 |
32 |
33 |
34 | 16
35 |
36 |
37 |
38 | Welcome to the Civil workbench!
39 |
40 |
41 |
42 | -
43 |
44 |
45 | <html><head/><body><p>This appears to be the first time that you are using the Civil workbench. If you press OK, the next screen will propose you to set a couple of typical FreeCAD options that are suitable for civil work. You can change these options anytime later under menu <span style=" font-weight:600;">Edit -> Preferences</span></p></body></html>
46 |
47 |
48 | true
49 |
50 |
51 |
52 | -
53 |
54 |
55 |
56 | 16
57 |
58 |
59 |
60 | Keep updated!
61 |
62 |
63 |
64 | -
65 |
66 |
67 | <html><head/><body><p>The Civil workbench is a work-in-progress and will change quite often. Make sure you <span style=" font-weight:600;">update</span> it regularly.</p></body></html>
68 |
69 |
70 | true
71 |
72 |
73 |
74 | -
75 |
76 |
77 | Qt::Horizontal
78 |
79 |
80 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | buttonBox
90 | accepted()
91 | Dialog
92 | accept()
93 |
94 |
95 | 248
96 | 254
97 |
98 |
99 | 157
100 | 274
101 |
102 |
103 |
104 |
105 | buttonBox
106 | rejected()
107 | Dialog
108 | reject()
109 |
110 |
111 | 316
112 | 260
113 |
114 |
115 | 286
116 | 274
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/osafe_widgets/draw_strip.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 241
10 | 162
11 |
12 |
13 |
14 | Create Base of Foundation
15 |
16 |
17 | -
18 |
19 | -
20 |
21 |
22 | cm
23 |
24 |
25 | 1
26 |
27 |
28 | 1000
29 |
30 |
31 | 5
32 |
33 |
34 | 100
35 |
36 |
37 |
38 | -
39 |
40 |
41 | cm
42 |
43 |
44 | 0
45 |
46 |
47 | 1000
48 |
49 |
50 | 5
51 |
52 |
53 | 50
54 |
55 |
56 |
57 | -
58 |
59 |
60 | Width
61 |
62 |
63 |
64 | -
65 |
66 |
67 | Left Width
68 |
69 |
70 |
71 | -
72 |
73 |
74 | cm
75 |
76 |
77 | 0
78 |
79 |
80 | 1000
81 |
82 |
83 | 5
84 |
85 |
86 | 50
87 |
88 |
89 |
90 | -
91 |
92 |
93 | Strip Layer
94 |
95 |
96 |
97 | -
98 |
99 |
100 | Right Width
101 |
102 |
103 |
104 | -
105 |
106 | -
107 |
108 | A
109 |
110 |
111 | -
112 |
113 | B
114 |
115 |
116 | -
117 |
118 | other
119 |
120 |
121 |
122 |
123 | -
124 |
125 | -
126 |
127 | Center
128 |
129 |
130 | -
131 |
132 | Left
133 |
134 |
135 | -
136 |
137 | Right
138 |
139 |
140 |
141 |
142 | -
143 |
144 |
145 | Align
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | strip_layer
155 | align
156 | width_spinbox
157 | left_width_spinbox
158 | right_width_spinbox
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/osafe_widgets/export/export_to_dxf.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 285
10 | 256
11 |
12 |
13 |
14 | Export Model to DXF
15 |
16 |
17 |
18 | :/osafe_images/dxf.svg :/osafe_images/dxf.svg
19 |
20 |
21 | -
22 |
23 |
24 | Columns
25 |
26 |
27 | true
28 |
29 |
30 |
31 | -
32 |
33 |
34 | Punches
35 |
36 |
37 |
38 | :/osafe_images/punch.svg :/osafe_images/punch.svg
39 |
40 |
41 | true
42 |
43 |
44 |
45 | -
46 |
47 | -
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | *.dxf
57 |
58 |
59 |
60 | -
61 |
62 |
63 | Browse
64 |
65 |
66 |
67 |
68 |
69 | -
70 |
71 | -
72 |
73 |
74 | Export
75 |
76 |
77 |
78 | :/safe/osafe_images/dxf.svg :/safe/osafe_images/dxf.svg
79 |
80 |
81 |
82 | 40
83 | 40
84 |
85 |
86 |
87 |
88 | -
89 |
90 |
91 | Cancel
92 |
93 |
94 |
95 | :/safe/osafe_images/cancel.png :/safe/osafe_images/cancel.png
96 |
97 |
98 |
99 | 40
100 | 40
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/osafe_widgets/force_panel.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 201
10 | 149
11 |
12 |
13 |
14 | Assign Loads
15 |
16 |
17 |
18 | :/safe/osafe_images/force.svg :/safe/osafe_images/force.svg
19 |
20 |
21 | -
22 |
23 |
24 | LoadCase
25 |
26 |
27 |
28 | -
29 |
30 |
31 | true
32 |
33 |
34 |
35 | -
36 |
37 |
38 | Value
39 |
40 |
41 |
42 | -
43 |
44 |
45 | Kg / m2
46 |
47 |
48 | 100000
49 |
50 |
51 | 5
52 |
53 |
54 | 200
55 |
56 |
57 |
58 | -
59 |
60 |
61 | Assign
62 |
63 |
64 |
65 | :/safe/osafe_images/force.svg :/safe/osafe_images/force.svg
66 |
67 |
68 |
69 | 60
70 | 60
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/osafe_widgets/import_from_dxf.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 247
10 | 183
11 |
12 |
13 |
14 | Import DXF Model
15 |
16 |
17 |
18 | :/osafe_images/import_dxf.svg :/osafe_images/import_dxf.svg
19 |
20 |
21 | -
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | *.dxf
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Browse
40 |
41 |
42 |
43 |
44 |
45 | -
46 |
47 | -
48 |
49 |
50 | Scale
51 |
52 |
53 |
54 | -
55 |
56 |
57 | 3
58 |
59 |
60 | 100000.000000000000000
61 |
62 |
63 | 1000.000000000000000
64 |
65 |
66 |
67 |
68 |
69 | -
70 |
71 | -
72 |
73 |
74 | Import
75 |
76 |
77 |
78 | :/safe/osafe_images/import_dxf.svg :/safe/osafe_images/import_dxf.svg
79 |
80 |
81 |
82 | 40
83 | 40
84 |
85 |
86 |
87 |
88 | -
89 |
90 |
91 | Cancel
92 |
93 |
94 |
95 | :/safe/osafe_images/cancel.png :/safe/osafe_images/cancel.png
96 |
97 |
98 |
99 | 40
100 | 40
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/osafe_widgets/wall_panel.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 207
10 | 205
11 |
12 |
13 |
14 | Create Wall
15 |
16 |
17 |
18 | :/safe/osafe_images/wall.svg :/safe/osafe_images/wall.svg
19 |
20 |
21 | -
22 |
23 |
24 | Kg/m2
25 |
26 |
27 | 50
28 |
29 |
30 | 10000
31 |
32 |
33 | 5
34 |
35 |
36 | 300
37 |
38 |
39 |
40 | -
41 |
42 |
43 | Unit Weight
44 |
45 |
46 |
47 | -
48 |
49 |
50 | Create
51 |
52 |
53 |
54 | :/safe/osafe_images/wall.svg :/safe/osafe_images/wall.svg
55 |
56 |
57 |
58 | 60
59 | 60
60 |
61 |
62 |
63 |
64 | -
65 |
66 |
67 | Height
68 |
69 |
70 |
71 | -
72 |
73 |
74 | Create Blocks
75 |
76 |
77 |
78 | -
79 |
80 |
81 |
82 |
83 |
84 | m
85 |
86 |
87 | 0.100000000000000
88 |
89 |
90 | 20.000000000000000
91 |
92 |
93 | 0.100000000000000
94 |
95 |
96 | 3.200000000000000
97 |
98 |
99 |
100 | -
101 |
102 |
103 | Load Pattern
104 |
105 |
106 |
107 | -
108 |
109 |
110 | true
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 | OSAFE
3 | This is a workbench for FreeCAD that creates foundation model from CSI ETABS model results.
4 | 2022.05.29
5 | Raeyat Roknabadi Ebrahim
6 | LGPL-2.1-or-later
7 | https://github.com/ebrahimraeyat/OSAFE
8 | https://github.com/ebrahimraeyat/OSAFE/wiki
9 | osafe_images/safe.png
10 |
11 |
12 |
13 | OSAFE
14 | ./
15 | comtypes
16 | etabs-api
17 | pydocx
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | #
2 | # This file is autogenerated by pip-compile
3 | # To update, run:
4 | #
5 | # pip-compile --output-file requirements.txt requirements.in
6 | #
7 | et-xmlfile>=1.0.1 # via openpyxl
8 | jdcal>=1.4 # via openpyxl
9 | numpy>=1.15.4 # via pandas
10 | openpyxl>=2.5.11
11 | pandas>=0.23.4
12 | python-dateutil>=2.7.5 # via pandas
13 | pytz>=2018.7 # via pandas
14 | six>=1.11.0 # via python-dateutil
15 | xlrd>=1.1.0
16 |
--------------------------------------------------------------------------------
/test/osafe_import_export/test_report.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | import matplotlib.pyplot as plt
5 |
6 | # path to FreeCAD
7 | FREECADPATH = 'G:\\program files\\FreeCAD 0.19\\bin'
8 | sys.path.append(FREECADPATH)
9 | import FreeCAD
10 |
11 | punch_path = Path(__file__).parent.parent.parent
12 | etabs_api_path = punch_path.parent / 'etabs_api'
13 | sys.path.insert(0, str(punch_path))
14 | sys.path.insert(1, str(etabs_api_path))
15 | from osafe_import_export import report
16 |
17 | from python_functions import get_temp_filepath
18 | from freecad_funcs import open_file
19 |
20 |
21 | import pandas as pd
22 |
23 | filename = punch_path / 'test' / 'test_files' / 'freecad' / 'base_plate.FCStd'
24 | circle_filename = punch_path / 'test' / 'test_files' / 'freecad' / 'circle_column.FCStd'
25 | document= FreeCAD.openDocument(str(filename))
26 | circle_document= FreeCAD.openDocument(str(circle_filename))
27 |
28 | def test_get_punch_picture():
29 | punch = document.Punch
30 | filename = get_temp_filepath(suffix='jpg', random=True)
31 | fname = report.get_punch_picture(punch, filename=filename)
32 | assert fname.exists()
33 | open_file(fname)
34 |
35 | def test_get_punch_picture_circle():
36 | punch = circle_document.Punch009
37 | filename = get_temp_filepath(suffix='jpg', random=True)
38 | fname = report.get_punch_picture(punch, filename=filename)
39 | assert fname.exists()
40 | open_file(fname)
41 |
42 | def test_add_equivalent_column():
43 | punch = document.Punch
44 | fig = plt.figure()
45 | ax1 = fig.add_subplot(211, aspect='equal')
46 | plt.axis('off')
47 | report.add_equivalent_column(punch, ax1)
48 | filename = get_temp_filepath(suffix='jpg', random=True)
49 | fig.savefig(filename)
50 | assert filename.exists()
51 | open_file(filename)
52 |
53 | def test_add_punch_edges_to_ax():
54 | punch = document.Punch
55 | fig = plt.figure()
56 | ax1 = fig.add_subplot(211, aspect='equal')
57 | plt.axis('off')
58 | report.add_punch_edges_to_ax(punch, ax1)
59 | filename = get_temp_filepath(suffix='jpg', random=True)
60 | fig.savefig(filename)
61 |
62 | def test_add_punch_edges_to_ax_circle():
63 | punch = circle_document.Punch009
64 | fig = plt.figure()
65 | ax1 = fig.add_subplot(211, aspect='equal')
66 | plt.axis('off')
67 | report.add_punch_edges_to_ax(punch, ax1)
68 | filename = get_temp_filepath(suffix='jpg', random=True)
69 | fig.savefig(filename)
70 | assert filename.exists()
71 | open_file(filename)
72 |
73 | def test_export_dataframe_to_docx():
74 | punch = document.Punch
75 | df = pd.DataFrame(list(punch.combos_ratio.items()), columns=['Combo', 'Ratio'])
76 | doc = report.export_dataframe_to_docx(df)
77 | filename = get_temp_filepath(suffix='docx', random=True)
78 | doc.save(filename)
79 |
80 | def test_create_report():
81 | punch = document.Punch
82 | filename = get_temp_filepath(suffix='docx', random=True)
83 | report.create_report(punch, filename)
84 | assert filename.exists()
85 | open_file(filename)
86 |
87 | def test_create_report_circle():
88 | punch = circle_document.Punch009
89 | filename = get_temp_filepath(suffix='docx', random=True)
90 | report.create_report(punch, filename)
91 | assert filename.exists()
92 | open_file(filename)
93 |
94 | # def test_get_edges_direction_in_punch():
95 | # punch = document.Punch
96 | # edges_direction = report.get_edges_direction_in_punch(punch)
97 | # assert list(edges_direction.values()) == ['BOT', 'RIGHT', 'TOP']
98 |
99 | def test_export_dict_to_doc():
100 | d = {'location': 'center', 'id': 227}
101 | doc = report.export_dict_to_doc(d, [])
102 | filename = get_temp_filepath(suffix='docx', random=True)
103 | doc.save(filename)
104 | assert True
105 |
106 | def test_add_punch_properties_to_doc():
107 | punch = document.Punch
108 | doc = report.add_punch_properties_to_doc(punch)
109 | filename = get_temp_filepath(suffix='docx', random=True)
110 | doc.save(filename)
111 | assert True
112 |
113 | def test_create_punches_report():
114 | filename = get_temp_filepath(suffix='docx', random=True)
115 | report.create_punches_report(document, filename)
116 |
117 | def test_create_punches_report_circle():
118 | filename = get_temp_filepath(suffix='docx', random=True)
119 | report.create_punches_report(circle_document, filename)
120 |
121 |
122 | if __name__ == '__main__':
123 | # test_get_punch_picture()
124 | test_create_report()
125 | # test_add_punch_properties_to_doc()
126 | # test_export_dict_to_doc()
127 | # test_create_punches_report()
--------------------------------------------------------------------------------
/test/osafe_objects/test_base_plate.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | import pytest
5 |
6 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
7 | sys.path.append(FREECADPATH)
8 |
9 | import FreeCAD
10 |
11 |
12 |
13 | punch_path = Path(__file__).parent.parent.parent
14 | sys.path.insert(0, str(punch_path))
15 | from osafe_objects import base_plate
16 |
17 |
18 | def test_make_base_plate():
19 | doc = FreeCAD.newDocument()
20 | FreeCAD.setActiveDocument(doc.Name)
21 | import Arch
22 | col = Arch.makeStructure()
23 | col.recompute(True)
24 | bx = 500
25 | by = 600
26 | bp = base_plate.make_base_plate(bx=bx, by=by, column=col.Label)
27 | bp.recompute(True)
28 | assert hasattr(col, 'base_plate')
29 | assert col.base_plate.Name == bp.Name
30 | assert bp.Bx == bx
31 | assert bp.By == by
32 |
33 | if __name__ == '__main__':
34 | test_make_base_plate()
--------------------------------------------------------------------------------
/test/osafe_objects/test_osafe_rebar.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | import pytest
5 |
6 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
7 | sys.path.append(FREECADPATH)
8 |
9 | import FreeCAD
10 |
11 |
12 |
13 | punch_path = Path(__file__).parent.parent.parent
14 | sys.path.insert(0, str(punch_path))
15 | from osafe_objects import osafe_rebar
16 |
17 | filename_rashidzadeh = Path(__file__).parent.parent / 'test_files' / 'freecad' / 'rashidzadeh.FCStd'
18 |
19 |
20 |
21 | def test_make_rebars():
22 | doc = FreeCAD.openDocument(str(filename_rashidzadeh))
23 | rebars = osafe_rebar.make_rebars()
24 | FreeCAD.ActiveDocument.recompute()
25 | assert len(rebars.Group) == len(doc.Foundation.base_foundations)
26 | for rebar in rebars.Group:
27 | assert not rebar.Shape.isNull()
28 |
29 | def test_make_rebar_from_scratch():
30 | doc = FreeCAD.newDocument()
31 | rebar = osafe_rebar.make_rebar_from_scratch(doc=doc)
32 | FreeCAD.ActiveDocument.recompute()
33 | assert not rebar.Shape.isNull()
34 |
35 | if __name__ == '__main__':
36 | test_make_rebars()
--------------------------------------------------------------------------------
/test/osafe_objects/test_strip.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | import pytest
5 |
6 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
7 | sys.path.append(FREECADPATH)
8 |
9 | import FreeCAD
10 | import Part
11 | import Draft
12 |
13 |
14 |
15 | punch_path = Path(__file__).parent.parent.parent
16 | sys.path.insert(0, str(punch_path))
17 | from osafe_objects.strip import make_strip
18 |
19 | filename_rashidzadeh = Path(__file__).parent.parent / 'test_files' / 'freecad' / 'rashidzadeh.FCStd'
20 |
21 |
22 |
23 | def test_make_strip():
24 | FreeCAD.newDocument()
25 | # Part wire
26 | p11 = FreeCAD.Vector(0, 0, 0)
27 | p22 = FreeCAD.Vector(10000, 0, 0)
28 | wire = Part.Wire(Part.makeLine(p11, p22))
29 | strip = make_strip(base=wire)
30 | FreeCAD.ActiveDocument.recompute()
31 | assert strip.Shape.Area == 10000 * 1000
32 | assert strip.Shape.BoundBox.YMax == 500
33 | assert strip.Shape.BoundBox.YMin == -500
34 | # Draft wire
35 | wire = Draft.make_wire(wire)
36 | strip = make_strip(base=wire)
37 | FreeCAD.ActiveDocument.recompute()
38 | assert strip.Shape.Area == 10000 * 1000
39 | assert strip.Shape.BoundBox.YMax == 500
40 | assert strip.Shape.BoundBox.YMin == -500
41 |
42 | if __name__ == '__main__':
43 | test_make_strip()
--------------------------------------------------------------------------------
/test/test_beam.py:
--------------------------------------------------------------------------------
1 | import math
2 | import sys
3 | from pathlib import Path
4 |
5 | import pytest
6 |
7 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
8 | sys.path.append(FREECADPATH)
9 |
10 | import FreeCAD
11 |
12 | filename_base_plate = Path(__file__).parent / 'test_files' / 'freecad' / 'base_plate.FCStd'
13 | document_base_plate = FreeCAD.openDocument(str(filename_base_plate))
14 |
15 |
16 | punch_path = Path(__file__).parent.parent
17 | sys.path.insert(0, str(punch_path))
18 |
19 | from osafe_objects import beam, punch
20 |
21 | def test_make_beam():
22 | p1 = FreeCAD.Vector(0, 0, 0)
23 | p2 = FreeCAD.Vector(1, 0, 0)
24 | beam.make_beam(p1, p2)
25 | assert True
26 |
27 | def test_punch_reinforcement():
28 | foun = document_base_plate.Foundation
29 | col = document_base_plate.getObjectsByLabel('C1_Story1')[0]
30 | p = punch.make_punch(foun, col)
31 | p.Use_Reinforcement = True
32 | p.Proxy.execute(p)
33 | assert True
34 |
35 |
36 |
37 |
38 | if __name__ == '__main__':
39 | test_make_punch()
--------------------------------------------------------------------------------
/test/test_etabs_foundation.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 |
5 | FREECADPATH = 'G:\\program files\\FreeCAD 0.19\\bin'
6 | sys.path.append(FREECADPATH)
7 |
8 | import FreeCAD
9 |
10 | filename_base_foundation = Path(__file__).parent / 'test_files' / 'freecad' / 'base_foundation.FCStd'
11 | document_base_foundation = FreeCAD.openDocument(str(filename_base_foundation))
12 |
13 |
14 | punch_path = Path(__file__).parent.parent
15 | sys.path.insert(0, str(punch_path))
16 | from osafe_objects import etabs_foundation
17 |
18 |
19 | def test_make_foundation():
20 | bfs = []
21 | for o in document_base_foundation.Objects:
22 | if hasattr(o, 'Proxy') and o.Proxy and o.Proxy.Type == 'BaseFoundation':
23 | bfs.append(o)
24 | ret = etabs_foundation.make_foundation(base_foundations=bfs)
25 | assert True
26 |
27 | def test_change_foundation_height():
28 | bfs = []
29 | for o in document_base_foundation.Objects:
30 | if hasattr(o, 'Proxy') and o.Proxy and o.Proxy.Type == 'BaseFoundation':
31 | bfs.append(o)
32 | ret = etabs_foundation.make_foundation(base_foundations=bfs)
33 | ret.height = 810
34 | document_base_foundation.recompute([ret])
35 | assert ret.height_punch.Value == 810
36 |
37 |
38 |
39 |
40 | if __name__ == '__main__':
41 | test_make_foundation()
--------------------------------------------------------------------------------
/test/test_etabs_punch.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | # path to FreeCAD.so
5 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
6 | sys.path.append(FREECADPATH)
7 | import FreeCAD
8 |
9 | punch_path = Path(__file__).parent.parent
10 | sys.path.insert(0, str(punch_path))
11 | from osafe_py_widgets import etabs_punch
12 | document= FreeCAD.newDocument()
13 | etabs = etabs_punch.EtabsPunch(beam_names=['114', '115', '116'])
14 |
15 | # def test_create_vectors():
16 | # etabs.create_vectors()
17 | # assert True
18 |
19 | def test_create_slabs_plan():
20 | etabs.create_slabs_plan()
21 |
22 | def test_create_columns():
23 | etabs.create_columns()
24 |
25 | def test_import_load_combos():
26 | etabs = etabs_punch.EtabsPunch()
27 | etabs.import_data(import_load_combos=True)
28 |
29 | if __name__ == '__main__':
30 | test_import_load_combos()
--------------------------------------------------------------------------------
/test/test_f2k_object.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 |
5 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
6 | sys.path.append(FREECADPATH)
7 |
8 | import FreeCAD
9 |
10 | # filename_base_plate = Path(__file__).absolute().parent.parent / 'test_files' / 'freecad' / 'base_plate.FCStd'
11 | # document_base_plate = FreeCAD.openDocument(str(filename_base_plate))
12 |
13 |
14 | punch_path = Path(__file__).absolute().parent.parent
15 | sys.path.insert(0, str(punch_path))
16 |
17 |
18 | def test_make_safe_f2k():
19 | FreeCAD.newDocument()
20 | from osafe_objects import f2k_object
21 | f2k_object.make_safe_f2k()
22 | assert True
23 |
24 |
25 | if __name__ == '__main__':
26 | test_make_safe_f2k()
--------------------------------------------------------------------------------
/test/test_files/.~lock.davoodabadi_dynamic.xlsx#:
--------------------------------------------------------------------------------
1 | ,ebi,manjaro,14.10.2018 20:02,file:///home/ebi/.config/libreoffice/4;
--------------------------------------------------------------------------------
/test/test_files/davoodabadi_dynamic.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/davoodabadi_dynamic.xlsx
--------------------------------------------------------------------------------
/test/test_files/freecad/adampira.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/adampira.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/base_foundation.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/base_foundation.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/base_plate.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/base_plate.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/circle_column.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/circle_column.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/kazemi.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/kazemi.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/khalaji.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/khalaji.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/mat.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/mat.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/rashidzadeh.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/rashidzadeh.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/strip.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/strip.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/strip_foundation.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/strip_foundation.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/test.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/test.FCStd
--------------------------------------------------------------------------------
/test/test_files/freecad/test_p.FCStd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/freecad/test_p.FCStd
--------------------------------------------------------------------------------
/test/test_files/khojasteh_97-07-18.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/khojasteh_97-07-18.xlsx
--------------------------------------------------------------------------------
/test/test_files/safdari.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/safdari.xlsx
--------------------------------------------------------------------------------
/test/test_files/sattari_safe.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebrahimraeyat/OSAFE/57c76763eb14942eaea848f773886f8590bcae54/test/test_files/sattari_safe.xlsx
--------------------------------------------------------------------------------
/test/test_geom.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | FREECADPATH = 'G:\\program files\\FreeCAD 0.19\\bin'
5 | sys.path.append(FREECADPATH)
6 |
7 | import FreeCAD
8 |
9 |
10 | punch_path = Path(__file__).absolute().parent.parent
11 | sys.path.insert(0, str(punch_path))
12 |
13 | from old_punch import geom
14 |
15 | def test_make_column():
16 | bx = 400
17 | by = 600
18 | center = FreeCAD.Vector(1000, 1000, 0)
19 | d = {}
20 | FreeCAD.newDocument()
21 | col = geom.make_column(bx, by, center, d)
22 | assert hasattr(col, 'Base') and hasattr(col.Base, 'Height')
23 | assert col.Base.Height == 600
24 |
25 |
26 | if __name__ == '__main__':
27 | test_make_column()
--------------------------------------------------------------------------------
/test/test_opening.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | # path to FreeCAD.so
5 | FREECADPATH = 'G:\\program files\\FreeCAD 0.19\\bin'
6 | sys.path.append(FREECADPATH)
7 | import FreeCAD
8 |
9 | punch_path = Path(__file__).absolute().parent.parent
10 | sys.path.insert(0, str(punch_path))
11 | from osafe_objects.opening import make_opening
12 | document= FreeCAD.newDocument()
13 |
14 | def test_make_opening():
15 | x1 = 10
16 | x2 = 25
17 | y1 = 7
18 | y2 = 17
19 | p1=FreeCAD.Vector(x1, y1, 0)
20 | p2=FreeCAD.Vector(x2, y1, 0)
21 | p3=FreeCAD.Vector(x2, y2, 0)
22 | p4=FreeCAD.Vector(x1, y2, 0)
23 | points = [p1, p2, p3, p4]
24 | obj = make_opening(
25 | points=points,
26 | height = 3,
27 | doc=document,
28 | )
29 | assert obj.plan.Area == 15 * 10
30 |
31 |
32 | if __name__ == '__main__':
33 | test_make_opening()
34 |
--------------------------------------------------------------------------------
/test/test_punch.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | import pytest
5 |
6 | FREECADPATH = 'G:\\program files\\FreeCAD 0.21\\bin'
7 | sys.path.append(FREECADPATH)
8 |
9 | import FreeCAD
10 |
11 | filename_base_plate = Path(__file__).parent / 'test_files' / 'freecad' / 'base_plate.FCStd'
12 | document_base_plate = FreeCAD.openDocument(str(filename_base_plate))
13 |
14 |
15 | punch_path = Path(__file__).absolute().parent.parent
16 | sys.path.insert(0, str(punch_path))
17 | from osafe_objects import punch
18 |
19 |
20 | def test_make_punch():
21 | foun = document_base_plate.Foundation
22 | col = document_base_plate.getObjectsByLabel('C1_Story1')[0]
23 | p = punch.make_punch(foun, col)
24 | p.Proxy.execute(p)
25 | assert True
26 |
27 | def test_punch_reinforcement():
28 | foun = document_base_plate.Foundation
29 | col = document_base_plate.getObjectsByLabel('C1_Story1')[0]
30 | p = punch.make_punch(foun, col)
31 | p.Use_Reinforcement = True
32 | p.Proxy.execute(p)
33 | assert True
34 |
35 | def test_rotated_punch():
36 | foun = document_base_plate.Foundation
37 | col = document_base_plate.getObjectsByLabel('C1_Story1')[0]
38 | p = punch.make_punch(foun, col)
39 | p.Proxy.execute(p)
40 | # Test Location
41 | for angle in range(0, 400, 10):
42 | col.AttachmentOffset = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),angle))
43 | document_base_plate.recompute()
44 | assert p.Location == 'Corner 1'
45 | # Test Ratio
46 | sec = col.Base
47 | sec.Height = 500
48 | sec.Width = 500
49 | # col.Proxy
50 | col.AttachmentOffset = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
51 | document_base_plate.recompute()
52 | assert col.Shape.BoundBox.XLength == 500
53 | assert col.Shape.BoundBox.YLength == 500
54 | # document_base_plate.recompute()
55 | for i in range(0, 90, 10):
56 | col.AttachmentOffset = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),i))
57 | p.Proxy.execute(p)
58 | r1 = p.Ratio
59 | print(20 * '=' + '\n')
60 | print(i, p.Ratio)
61 | print(20 * '=' + '\n')
62 | for angle in range(i+90, 720, 90):
63 | col.AttachmentOffset = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),angle))
64 | p.Proxy.execute(p)
65 | # document_base_plate.recompute()
66 | print(p.angle, p.Ratio)
67 | assert pytest.approx(float(r1), abs=.01) == pytest.approx(float(p.Ratio), abs=.01)
68 |
69 |
70 | if __name__ == '__main__':
71 | test_make_punch()
--------------------------------------------------------------------------------
/test/test_rectangular_slab.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | FREECADPATH = 'G:\\program files\\FreeCAD 0.19\\bin'
5 | sys.path.append(FREECADPATH)
6 |
7 | import FreeCAD
8 |
9 |
10 | punch_path = Path(__file__).absolute().parent.parent
11 | sys.path.insert(0, str(punch_path))
12 |
13 | import rectangular_slab
14 |
15 | def test_make_rectangular_slab():
16 | from beam import make_beam
17 | FreeCAD.newDocument()
18 | p1 = FreeCAD.Vector(0, 0, 0)
19 | p2 = FreeCAD.Vector(1000, 0, 0)
20 | p3 = FreeCAD.Vector(3000, 2000, 0)
21 | b1 = make_beam(p1, p2)
22 | b2 = make_beam(p2, p3)
23 | rectangular_slab.make_rectangular_slab(
24 | beams=[b1, b2],
25 | )
26 |
27 |
28 | if __name__ == '__main__':
29 | test_make_rectangular_slab()
--------------------------------------------------------------------------------
/test/test_trapezoidal_slab.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from pathlib import Path
3 |
4 | # path to FreeCAD.so
5 | FREECADPATH = 'G:\\program files\\FreeCAD 0.19\\bin'
6 | sys.path.append(FREECADPATH)
7 | import FreeCAD
8 |
9 | punch_path = Path(__file__).absolute().parent.parent
10 | sys.path.insert(0, str(punch_path))
11 | from trapezoidal_slab import make_trapezoidal_slab
12 | document= FreeCAD.newDocument()
13 |
14 | # def test_create_vectors():
15 | # etabs.create_vectors()
16 | # assert True
17 |
18 | def test_make_trapezoidal_slab():
19 | obj = make_trapezoidal_slab(p1=FreeCAD.Vector(0, 16400, 0),
20 | p2=FreeCAD.Vector(12210, 16400, 0),
21 | layer='A',
22 | design_type='column',
23 | swl='25 cm',
24 | swr=250,
25 | ewl=250,
26 | ewr=250,
27 | )
28 | assert obj.plan.Area == 12210 * 500
29 | assert obj.layer == 'A'
30 |
31 |
32 | if __name__ == '__main__':
33 | test_make_trapezoidal_slab()
34 |
--------------------------------------------------------------------------------