From 41484ccd9f0a865b6b5162b29a42f238fa54c29f Mon Sep 17 00:00:00 2001 From: Harshan S Date: Fri, 4 Jul 2025 09:56:10 +0530 Subject: [PATCH] pushing changes in spacing and capacity details and temporarily parked welded lap joint in cad/items directory --- src/drawing1.dxf | 3574 +++++++++++++++++ src/drawing2.dxf | 3574 +++++++++++++++++ src/flamegraph.svg | 0 src/osdag/Common.py | 62 +- src/osdag/_version.py | 2 +- src/osdag/cad/BBCad/BBCoverPlateBoltedCAD.py | 178 +- .../CCSpliceCoverPlateCAD/BoltedCAD.py | 90 +- src/osdag/cad/common_logic.py | 129 +- src/osdag/cad/items/LapJointWelded.py | 140 + src/osdag/cad/items/purlin.py | 70 + src/osdag/cut_trace_wrapper.py | 58 + .../data/ResourceFiles/images/purlin.jpg | Bin 0 -> 35127 bytes .../compression_member/compression.py | 2 +- .../connection/end_plate_connection.py | 10 +- .../connection/seated_angle_connection.py | 2 +- .../flexural_member/flexure_purlin.py | 3385 ++++++++++++++++ src/osdag/fuse_trace_wrapper.py | 57 + src/osdag/gui/BC2Cendplate.py | 638 +++ src/osdag/gui/Beam2ColEnddetailing.py | 1154 ++++++ src/osdag/gui/additionalfns.py | 9 + src/osdag/gui/b2bcoverplateweld.py | 290 ++ src/osdag/gui/b2cendplateSketch.py | 702 ++++ src/osdag/gui/baseplatedetailing.py | 611 +++ src/osdag/gui/baseplatedetailinghollow.py | 452 +++ src/osdag/gui/beam2beamcoverplatedetailing.py | 393 ++ ...eamcoverplatedetailing_capacity_details.py | 586 +++ src/osdag/gui/capacity_details_finPlate.py | 444 ++ src/osdag/gui/cleatangledetailing.py | 299 ++ src/osdag/gui/endplatecnndetailnig.py | 303 ++ src/osdag/gui/seatedanglespacing.py | 303 ++ src/osdag/gui/spacing.py | 297 ++ src/osdag/gui/ui_aboutosdag.py | 3 +- src/osdag/gui/ui_template.py | 226 +- src/osdag/osdagMainPage.py | 315 +- src/osdag/print_trace_wrapper.py | 49 + src/osdag/profile_output | 1 + src/osdag/trace_wrapper.py | 27 +- src/osdag/trace_wrapper_unique.py | 61 + src/osdag/utilities/__init__.py | 72 +- src/osdag/utils/common/component.py | 60 +- src/osdag/utils/common/load.py | 39 +- src/profile_output | Bin 0 -> 6643 bytes 42 files changed, 18353 insertions(+), 314 deletions(-) create mode 100644 src/drawing1.dxf create mode 100644 src/drawing2.dxf create mode 100644 src/flamegraph.svg create mode 100644 src/osdag/cad/items/LapJointWelded.py create mode 100644 src/osdag/cad/items/purlin.py create mode 100644 src/osdag/cut_trace_wrapper.py create mode 100644 src/osdag/data/ResourceFiles/images/purlin.jpg create mode 100644 src/osdag/design_type/flexural_member/flexure_purlin.py create mode 100644 src/osdag/fuse_trace_wrapper.py create mode 100644 src/osdag/gui/BC2Cendplate.py create mode 100644 src/osdag/gui/Beam2ColEnddetailing.py create mode 100644 src/osdag/gui/additionalfns.py create mode 100644 src/osdag/gui/b2bcoverplateweld.py create mode 100644 src/osdag/gui/b2cendplateSketch.py create mode 100644 src/osdag/gui/baseplatedetailing.py create mode 100644 src/osdag/gui/baseplatedetailinghollow.py create mode 100644 src/osdag/gui/beam2beamcoverplatedetailing.py create mode 100644 src/osdag/gui/beam2beamcoverplatedetailing_capacity_details.py create mode 100644 src/osdag/gui/capacity_details_finPlate.py create mode 100644 src/osdag/gui/cleatangledetailing.py create mode 100644 src/osdag/gui/endplatecnndetailnig.py create mode 100644 src/osdag/gui/seatedanglespacing.py create mode 100644 src/osdag/gui/spacing.py create mode 100644 src/osdag/print_trace_wrapper.py create mode 100644 src/osdag/profile_output create mode 100644 src/osdag/trace_wrapper_unique.py create mode 100644 src/profile_output diff --git a/src/drawing1.dxf b/src/drawing1.dxf new file mode 100644 index 000000000..4ff61c0bc --- /dev/null +++ b/src/drawing1.dxf @@ -0,0 +1,3574 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1024 + 9 +$ACADMAINTVER + 70 +6 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$LASTSAVEDBY + 1 +ezdxf + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +1e+20 + 20 +1e+20 + 30 +1e+20 + 9 +$EXTMAX + 10 +-1e+20 + 20 +-1e+20 + 30 +-1e+20 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +420.0 + 20 +297.0 + 9 +$ORTHOMODE + 70 +0 + 9 +$REGENMODE + 70 +1 + 9 +$FILLMODE + 70 +1 + 9 +$QTEXTMODE + 70 +0 + 9 +$MIRRTEXT + 70 +1 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 +1 + 9 +$TEXTSIZE + 40 +2.5 + 9 +$TRACEWID + 40 +1.0 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +0 + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 +256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 +0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +2.5 + 9 +$DIMEXO + 40 +0.625 + 9 +$DIMDLI + 40 +3.75 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +1.25 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +2.5 + 9 +$DIMCEN + 40 +2.5 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 +0 + 9 +$DIMLIM + 70 +0 + 9 +$DIMTIH + 70 +0 + 9 +$DIMTOH + 70 +0 + 9 +$DIMSE1 + 70 +0 + 9 +$DIMSE2 + 70 +0 + 9 +$DIMTAD + 70 +1 + 9 +$DIMZIN + 70 +8 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 +1 + 9 +$DIMSHO + 70 +1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 +0 + 9 +$DIMALTD + 70 +3 + 9 +$DIMALTF + 40 +0.03937007874 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 +1 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 +0 + 9 +$DIMSOXD + 70 +0 + 9 +$DIMSAH + 70 +0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +ISO-25 + 9 +$DIMCLRD + 70 +0 + 9 +$DIMCLRE + 70 +0 + 9 +$DIMCLRT + 70 +0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.625 + 9 +$DIMJUST + 70 +0 + 9 +$DIMSD1 + 70 +0 + 9 +$DIMSD2 + 70 +0 + 9 +$DIMTOLJ + 70 +0 + 9 +$DIMTZIN + 70 +8 + 9 +$DIMALTZ + 70 +0 + 9 +$DIMALTTZ + 70 +0 + 9 +$DIMUPT + 70 +0 + 9 +$DIMDEC + 70 +2 + 9 +$DIMTDEC + 70 +2 + 9 +$DIMALTU + 70 +2 + 9 +$DIMALTTD + 70 +3 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 +0 + 9 +$DIMADEC + 70 +0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 +0 + 9 +$DIMDSEP + 70 +44 + 9 +$DIMATFIT + 70 +3 + 9 +$DIMFRAC + 70 +0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 +2 + 9 +$DIMLWD + 70 +-2 + 9 +$DIMLWE + 70 +-2 + 9 +$DIMTMOVE + 70 +0 + 9 +$DIMFXL + 40 +1.0 + 9 +$DIMFXLON + 70 +0 + 9 +$DIMJOGANG + 40 +0.785398163397 + 9 +$DIMTFILL + 70 +0 + 9 +$DIMTFILLCLR + 70 +0 + 9 +$DIMARCSYM + 70 +0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$DIMTXTDIRECTION + 70 +0 + 9 +$LUNITS + 70 +2 + 9 +$LUPREC + 70 +4 + 9 +$SKETCHINC + 40 +1.0 + 9 +$FILLETRAD + 40 +10.0 + 9 +$AUNITS + 70 +0 + 9 +$AUPREC + 70 +2 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 +0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 +0 + 9 +$TDCREATE + 40 +2460755.074085648 + 9 +$TDUCREATE + 40 +2458532.153996898 + 9 +$TDUPDATE + 40 +2460755.0742013888 + 9 +$TDUUPDATE + 40 +2458532.1544311 + 9 +$TDINDWG + 40 +0.0 + 9 +$TDUSRTIMER + 40 +0.0 + 9 +$USRTIMER + 70 +1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 +0 + 9 +$PDMODE + 70 +0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 +0 + 9 +$SPLINETYPE + 70 +6 + 9 +$SPLINESEGS + 70 +8 + 9 +$HANDSEED + 5 +43 + 9 +$SURFTAB1 + 70 +6 + 9 +$SURFTAB2 + 70 +6 + 9 +$SURFTYPE + 70 +6 + 9 +$SURFU + 70 +6 + 9 +$SURFV + 70 +6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 +0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 +0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 +0 + 9 +$USERI2 + 70 +0 + 9 +$USERI3 + 70 +0 + 9 +$USERI4 + 70 +0 + 9 +$USERI5 + 70 +0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 +1 + 9 +$SHADEDGE + 70 +3 + 9 +$SHADEDIF + 70 +70 + 9 +$TILEMODE + 70 +1 + 9 +$MAXACTVP + 70 +64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 +0 + 9 +$PEXTMIN + 10 +1e+20 + 20 +1e+20 + 30 +1e+20 + 9 +$PEXTMAX + 10 +-1e+20 + 20 +-1e+20 + 30 +-1e+20 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +420.0 + 20 +297.0 + 9 +$UNITMODE + 70 +0 + 9 +$VISRETAIN + 70 +1 + 9 +$PLINEGEN + 70 +0 + 9 +$PSLTSCALE + 70 +1 + 9 +$TREEDEPTH + 70 +3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 +0 + 9 +$CMLSCALE + 40 +20.0 + 9 +$PROXYGRAPHICS + 70 +1 + 9 +$MEASUREMENT + 70 +1 + 9 +$CELWEIGHT +370 +-1 + 9 +$ENDCAPS +280 +0 + 9 +$JOINSTYLE +280 +0 + 9 +$LWDISPLAY +290 +0 + 9 +$INSUNITS + 70 +6 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 +1 + 9 +$CEPSNTYPE +380 +0 + 9 +$PSTYLEMODE +290 +1 + 9 +$FINGERPRINTGUID + 2 +{B7445AA8-2B75-4440-9CE3-F09159ECE861} + 9 +$VERSIONGUID + 2 +{B617003B-928B-49A0-972A-1DDCE44D22C2} + 9 +$EXTNAMES +290 +1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 +0 + 9 +$SORTENTS +280 +127 + 9 +$INDEXCTL +280 +0 + 9 +$HIDETEXT +280 +1 + 9 +$XCLIPFRAME +280 +1 + 9 +$HALOGAP +280 +0 + 9 +$OBSCOLOR + 70 +257 + 9 +$OBSLTYPE +280 +0 + 9 +$INTERSECTIONDISPLAY +280 +0 + 9 +$INTERSECTIONCOLOR + 70 +257 + 9 +$DIMASSOC +280 +2 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 +0 + 9 +$LENSLENGTH + 40 +50.0 + 9 +$CAMERAHEIGHT + 40 +0.0 + 9 +$STEPSPERSEC + 40 +24.0 + 9 +$STEPSIZE + 40 +100.0 + 9 +$3DDWFPREC + 40 +2.0 + 9 +$PSOLWIDTH + 40 +0.005 + 9 +$PSOLHEIGHT + 40 +0.08 + 9 +$LOFTANG1 + 40 +1.570796326795 + 9 +$LOFTANG2 + 40 +1.570796326795 + 9 +$LOFTMAG1 + 40 +0.0 + 9 +$LOFTMAG2 + 40 +0.0 + 9 +$LOFTPARAM + 70 +7 + 9 +$LOFTNORMALS +280 +1 + 9 +$LATITUDE + 40 +37.795 + 9 +$LONGITUDE + 40 +-122.394 + 9 +$NORTHDIRECTION + 40 +0.0 + 9 +$TIMEZONE + 70 +-8000 + 9 +$LIGHTGLYPHDISPLAY +280 +1 + 9 +$TILEMODELIGHTSYNCH +280 +1 + 9 +$CMATERIAL +347 +20 + 9 +$SOLIDHIST +280 +0 + 9 +$SHOWHIST +280 +1 + 9 +$DWFFRAME +280 +2 + 9 +$DGNFRAME +280 +2 + 9 +$REALWORLDSCALE +290 +1 + 9 +$INTERFERECOLOR + 62 +256 + 9 +$CSHADOW +280 +0 + 9 +$SHADOWPLANELOCATION + 40 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +SUN + 2 +AcDbSun + 3 +SCENEOE + 90 +1153 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 +4095 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 +1153 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 +1153 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 +4095 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +MLEADERSTYLE + 2 +AcDbMLeaderStyle + 3 +ACDB_MLEADERSTYLE_CLASS + 90 +4095 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +CELLSTYLEMAP + 2 +AcDbCellStyleMap + 3 +ObjectDBX Classes + 90 +1152 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +MENTALRAYRENDERSETTINGS + 2 +AcDbMentalRayRenderSettings + 3 +SCENEOE + 90 +1024 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +ACDBDETAILVIEWSTYLE + 2 +AcDbDetailViewStyle + 3 +ObjectDBX Classes + 90 +1025 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +ACDBSECTIONVIEWSTYLE + 2 +AcDbSectionViewStyle + 3 +ObjectDBX Classes + 90 +1025 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +RASTERVARIABLES + 2 +AcDbRasterVariables + 3 +ISM + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +ACDBPLACEHOLDER + 2 +AcDbPlaceHolder + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +LAYOUT + 2 +AcDbLayout + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 +1 + 0 +VPORT + 5 +23 +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 +0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +0.0 + 22 +0.0 + 13 +0.0 + 23 +0.0 + 14 +0.5 + 24 +0.5 + 15 +0.5 + 25 +0.5 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +1000.0 + 41 +1.34 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 +0 + 72 +1000 + 73 +1 + 74 +3 + 75 +0 + 76 +0 + 77 +0 + 78 +0 +281 +0 + 65 +0 +146 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +2 +330 +0 +100 +AcDbSymbolTable + 70 +3 + 0 +LTYPE + 5 +24 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +25 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +26 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 +2 + 0 +LAYER + 5 +27 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 +0 + 62 +7 + 6 +Continuous +370 +-3 +390 +13 +347 +21 + 0 +LAYER + 5 +28 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Defpoints + 70 +0 + 62 +7 + 6 +Continuous +290 +0 +370 +-3 +390 +13 +347 +21 + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 +1 + 0 +STYLE + 5 +29 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 +0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 +0 + 42 +2.5 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 +3 + 0 +APPID + 5 +2A +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 +0 + 0 +APPID + 5 +40 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +HATCHBACKGROUNDCOLOR + 70 +0 + 0 +APPID + 5 +41 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +EZDXF + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +4 +330 +0 +100 +AcDbSymbolTable + 70 +1 +100 +AcDbDimStyleTable + 0 +DIMSTYLE +105 +2B +330 +4 +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 +0 + 40 +1.0 + 41 +2.5 + 42 +0.625 + 43 +3.75 + 44 +1.25 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +2.5 +140 +2.5 +141 +2.5 +142 +0.0 +143 +0.03937007874 +144 +1.0 +145 +0.0 +146 +1.0 +147 +0.625 +148 +0.0 + 69 +0 + 70 +0 + 71 +0 + 72 +0 + 73 +0 + 74 +0 + 75 +0 + 76 +0 + 77 +1 + 78 +8 + 79 +3 +170 +0 +171 +3 +172 +1 +173 +0 +174 +0 +175 +0 +176 +0 +177 +0 +178 +0 +179 +2 +271 +2 +272 +2 +273 +2 +274 +3 +275 +0 +276 +0 +277 +2 +278 +44 +279 +0 +280 +0 +281 +0 +282 +0 +283 +0 +284 +8 +285 +0 +286 +0 +288 +0 +289 +3 +290 +0 +371 +-2 +372 +-2 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 +2 + 0 +BLOCK_RECORD + 5 +17 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +1A + 70 +0 +280 +1 +281 +0 + 0 +BLOCK_RECORD + 5 +1B +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +1E + 70 +0 +280 +1 +281 +0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +18 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +19 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +1C +330 +1B +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +1D +330 +1B +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LWPOLYLINE + 5 +2F +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbPolyline + 90 +5 + 70 +1 + 10 +0.0 + 20 +0.0 + 10 +115.0 + 20 +0.0 + 10 +115.0 + 20 +160.0 + 10 +0.0 + 20 +160.0 + 10 +0.0 + 20 +0.0 + 0 +CIRCLE + 5 +30 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +25.0 + 20 +30.0 + 30 +0.0 + 40 +5.0 + 0 +CIRCLE + 5 +31 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +75.0 + 20 +30.0 + 30 +0.0 + 40 +5.0 + 0 +CIRCLE + 5 +32 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +25.0 + 20 +80.0 + 30 +0.0 + 40 +5.0 + 0 +CIRCLE + 5 +33 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +75.0 + 20 +80.0 + 30 +0.0 + 40 +5.0 + 0 +CIRCLE + 5 +34 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +25.0 + 20 +130.0 + 30 +0.0 + 40 +5.0 + 0 +CIRCLE + 5 +35 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +75.0 + 20 +130.0 + 30 +0.0 + 40 +5.0 + 0 +DIMENSION + 5 +36 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +135.0 + 20 +55.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +125.0 + 23 +80.0 + 33 +0.0 + 14 +125.0 + 24 +30.0 + 34 +0.0 + 50 +90.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +37 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +140.0 + 20 +55.0 + 30 +0.0 + 40 +2.5 + 1 +pitch +100 +AcDbText + 0 +DIMENSION + 5 +38 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +135.0 + 20 +15.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +125.0 + 23 +0.0 + 33 +0.0 + 14 +125.0 + 24 +30.0 + 34 +0.0 + 50 +90.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +39 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +140.0 + 20 +15.0 + 30 +0.0 + 40 +2.5 + 1 +end dist. +100 +AcDbText + 0 +DIMENSION + 5 +3A +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +12.5 + 20 +-20.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +0.0 + 23 +-10.0 + 33 +0.0 + 14 +25.0 + 24 +-10.0 + 34 +0.0 + 50 +0.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +3B +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +12.5 + 20 +-25.0 + 30 +0.0 + 40 +2.5 + 1 +gauge₁ +100 +AcDbText + 0 +DIMENSION + 5 +3C +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +50.0 + 20 +-20.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +25.0 + 23 +-10.0 + 33 +0.0 + 14 +75.0 + 24 +-10.0 + 34 +0.0 + 50 +0.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +3D +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +50.0 + 20 +-25.0 + 30 +0.0 + 40 +2.5 + 1 +gauge₂ +100 +AcDbText + 0 +DIMENSION + 5 +3E +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +95.0 + 20 +-20.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +75.0 + 23 +-10.0 + 33 +0.0 + 14 +115.0 + 24 +-10.0 + 34 +0.0 + 50 +0.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +3F +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +95.0 + 20 +-25.0 + 30 +0.0 + 40 +2.5 + 1 +edge dist. +100 +AcDbText + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +A +330 +0 +100 +AcDbDictionary +280 +0 +281 +1 + 3 +ACAD_COLOR +350 +B + 3 +ACAD_GROUP +350 +C + 3 +ACAD_LAYOUT +350 +D + 3 +ACAD_MATERIAL +350 +E + 3 +ACAD_MLEADERSTYLE +350 +F + 3 +ACAD_MLINESTYLE +350 +10 + 3 +ACAD_PLOTSETTINGS +350 +11 + 3 +ACAD_PLOTSTYLENAME +350 +12 + 3 +ACAD_SCALELIST +350 +14 + 3 +ACAD_TABLESTYLE +350 +15 + 3 +ACAD_VISUALSTYLE +350 +16 + 3 +EZDXF_META +350 +2D + 0 +DICTIONARY + 5 +B +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +C +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +D +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Model +350 +1A + 3 +Layout1 +350 +1E + 0 +DICTIONARY + 5 +E +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +ByBlock +350 +1F + 3 +ByLayer +350 +20 + 3 +Global +350 +21 + 0 +DICTIONARY + 5 +F +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Standard +350 +2C + 0 +DICTIONARY + 5 +10 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Standard +350 +22 + 0 +DICTIONARY + 5 +11 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +ACDBDICTIONARYWDFLT + 5 +12 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Normal +350 +13 +100 +AcDbDictionaryWithDefault +340 +13 + 0 +ACDBPLACEHOLDER + 5 +13 +330 +12 + 0 +DICTIONARY + 5 +14 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +15 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +16 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +LAYOUT + 5 +1A +330 +D +100 +AcDbPlotSettings + 1 + + 4 +A3 + 6 + + 40 +7.5 + 41 +20.0 + 42 +7.5 + 43 +20.0 + 44 +420.0 + 45 +297.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +1024 + 72 +1 + 73 +0 + 74 +5 + 7 + + 75 +16 + 76 +0 + 77 +2 + 78 +300 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Model + 70 +1 + 71 +0 + 10 +0.0 + 20 +0.0 + 11 +420.0 + 21 +297.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +1e+20 + 24 +1e+20 + 34 +1e+20 + 15 +-1e+20 + 25 +-1e+20 + 35 +-1e+20 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +1 +330 +17 + 0 +LAYOUT + 5 +1E +330 +D +100 +AcDbPlotSettings + 1 + + 4 +A3 + 6 + + 40 +7.5 + 41 +20.0 + 42 +7.5 + 43 +20.0 + 44 +420.0 + 45 +297.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +0 + 72 +1 + 73 +0 + 74 +5 + 7 + + 75 +16 + 76 +0 + 77 +2 + 78 +300 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout1 + 70 +1 + 71 +1 + 10 +0.0 + 20 +0.0 + 11 +420.0 + 21 +297.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +1e+20 + 24 +1e+20 + 34 +1e+20 + 15 +-1e+20 + 25 +-1e+20 + 35 +-1e+20 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +1 +330 +1B + 0 +MATERIAL + 5 +1F +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E +100 +AcDbMaterial + 1 +ByBlock + 2 + + 70 +0 + 40 +1.0 + 71 +1 + 41 +1.0 + 91 +-1023410177 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 44 +0.5 + 73 +0 + 45 +1.0 + 46 +1.0 + 77 +1 + 4 + + 78 +1 + 79 +1 +170 +1 + 48 +1.0 +171 +1 + 6 + +172 +1 +173 +1 +174 +1 +140 +1.0 +141 +1.0 +175 +1 + 7 + +176 +1 +177 +1 +178 +1 +143 +1.0 +179 +1 + 8 + +270 +1 +271 +1 +272 +1 +145 +1.0 +146 +1.0 +273 +1 + 9 + +274 +1 +275 +1 +276 +1 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 94 +63 + 0 +MATERIAL + 5 +20 +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E +100 +AcDbMaterial + 1 +ByLayer + 2 + + 70 +0 + 40 +1.0 + 71 +1 + 41 +1.0 + 91 +-1023410177 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 44 +0.5 + 73 +0 + 45 +1.0 + 46 +1.0 + 77 +1 + 4 + + 78 +1 + 79 +1 +170 +1 + 48 +1.0 +171 +1 + 6 + +172 +1 +173 +1 +174 +1 +140 +1.0 +141 +1.0 +175 +1 + 7 + +176 +1 +177 +1 +178 +1 +143 +1.0 +179 +1 + 8 + +270 +1 +271 +1 +272 +1 +145 +1.0 +146 +1.0 +273 +1 + 9 + +274 +1 +275 +1 +276 +1 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 94 +63 + 0 +MATERIAL + 5 +21 +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E +100 +AcDbMaterial + 1 +Global + 2 + + 70 +0 + 40 +1.0 + 71 +1 + 41 +1.0 + 91 +-1023410177 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 44 +0.5 + 73 +0 + 45 +1.0 + 46 +1.0 + 77 +1 + 4 + + 78 +1 + 79 +1 +170 +1 + 48 +1.0 +171 +1 + 6 + +172 +1 +173 +1 +174 +1 +140 +1.0 +141 +1.0 +175 +1 + 7 + +176 +1 +177 +1 +178 +1 +143 +1.0 +179 +1 + 8 + +270 +1 +271 +1 +272 +1 +145 +1.0 +146 +1.0 +273 +1 + 9 + +274 +1 +275 +1 +276 +1 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 94 +63 + 0 +MLINESTYLE + 5 +22 +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMlineStyle + 2 +Standard + 70 +0 + 3 + + 62 +256 + 51 +90.0 + 52 +90.0 + 71 +2 + 49 +0.5 + 62 +256 + 6 +BYLAYER + 49 +-0.5 + 62 +256 + 6 +BYLAYER + 0 +MLEADERSTYLE + 5 +2C +102 +{ACAD_REACTORS +330 +F +102 +} +330 +F +100 +AcDbMLeaderStyle +179 +2 +170 +2 +171 +1 +172 +0 + 90 +2 + 40 +0.0 + 41 +0.0 +173 +1 + 91 +-1056964608 + 92 +-2 +290 +1 + 42 +2.0 +291 +1 + 43 +8.0 + 3 +Standard + 44 +4.0 +300 + +342 +29 +174 +1 +175 +1 +176 +0 +178 +1 + 93 +-1056964608 + 45 +4.0 +292 +0 +297 +0 + 46 +4.0 + 94 +-1056964608 + 47 +1.0 + 49 +1.0 +140 +1.0 +294 +1 +141 +0.0 +177 +0 +142 +1.0 +295 +0 +296 +0 +143 +3.75 +271 +0 +272 +9 +273 +9 + 0 +DICTIONARY + 5 +2D +330 +A +100 +AcDbDictionary +280 +1 +281 +1 + 3 +CREATED_BY_EZDXF +350 +2E + 3 +WRITTEN_BY_EZDXF +350 +42 + 0 +DICTIONARYVAR + 5 +2E +330 +2D +100 +DictionaryVariables +280 +0 + 1 +1.4.0 @ 2025-03-19T20:16:41.354920+00:00 + 0 +DICTIONARYVAR + 5 +42 +330 +2D +100 +DictionaryVariables +280 +0 + 1 +1.4.0 @ 2025-03-19T20:16:51.936662+00:00 + 0 +ENDSEC + 0 +EOF diff --git a/src/drawing2.dxf b/src/drawing2.dxf new file mode 100644 index 000000000..f41c30ef2 --- /dev/null +++ b/src/drawing2.dxf @@ -0,0 +1,3574 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1024 + 9 +$ACADMAINTVER + 70 +6 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$LASTSAVEDBY + 1 +ezdxf + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +1e+20 + 20 +1e+20 + 30 +1e+20 + 9 +$EXTMAX + 10 +-1e+20 + 20 +-1e+20 + 30 +-1e+20 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +420.0 + 20 +297.0 + 9 +$ORTHOMODE + 70 +0 + 9 +$REGENMODE + 70 +1 + 9 +$FILLMODE + 70 +1 + 9 +$QTEXTMODE + 70 +0 + 9 +$MIRRTEXT + 70 +1 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 +1 + 9 +$TEXTSIZE + 40 +2.5 + 9 +$TRACEWID + 40 +1.0 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +0 + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 +256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 +0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +2.5 + 9 +$DIMEXO + 40 +0.625 + 9 +$DIMDLI + 40 +3.75 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +1.25 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +2.5 + 9 +$DIMCEN + 40 +2.5 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 +0 + 9 +$DIMLIM + 70 +0 + 9 +$DIMTIH + 70 +0 + 9 +$DIMTOH + 70 +0 + 9 +$DIMSE1 + 70 +0 + 9 +$DIMSE2 + 70 +0 + 9 +$DIMTAD + 70 +1 + 9 +$DIMZIN + 70 +8 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 +1 + 9 +$DIMSHO + 70 +1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 +0 + 9 +$DIMALTD + 70 +3 + 9 +$DIMALTF + 40 +0.03937007874 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 +1 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 +0 + 9 +$DIMSOXD + 70 +0 + 9 +$DIMSAH + 70 +0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +ISO-25 + 9 +$DIMCLRD + 70 +0 + 9 +$DIMCLRE + 70 +0 + 9 +$DIMCLRT + 70 +0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.625 + 9 +$DIMJUST + 70 +0 + 9 +$DIMSD1 + 70 +0 + 9 +$DIMSD2 + 70 +0 + 9 +$DIMTOLJ + 70 +0 + 9 +$DIMTZIN + 70 +8 + 9 +$DIMALTZ + 70 +0 + 9 +$DIMALTTZ + 70 +0 + 9 +$DIMUPT + 70 +0 + 9 +$DIMDEC + 70 +2 + 9 +$DIMTDEC + 70 +2 + 9 +$DIMALTU + 70 +2 + 9 +$DIMALTTD + 70 +3 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 +0 + 9 +$DIMADEC + 70 +0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 +0 + 9 +$DIMDSEP + 70 +44 + 9 +$DIMATFIT + 70 +3 + 9 +$DIMFRAC + 70 +0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 +2 + 9 +$DIMLWD + 70 +-2 + 9 +$DIMLWE + 70 +-2 + 9 +$DIMTMOVE + 70 +0 + 9 +$DIMFXL + 40 +1.0 + 9 +$DIMFXLON + 70 +0 + 9 +$DIMJOGANG + 40 +0.785398163397 + 9 +$DIMTFILL + 70 +0 + 9 +$DIMTFILLCLR + 70 +0 + 9 +$DIMARCSYM + 70 +0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$DIMTXTDIRECTION + 70 +0 + 9 +$LUNITS + 70 +2 + 9 +$LUPREC + 70 +4 + 9 +$SKETCHINC + 40 +1.0 + 9 +$FILLETRAD + 40 +10.0 + 9 +$AUNITS + 70 +0 + 9 +$AUPREC + 70 +2 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 +0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 +0 + 9 +$TDCREATE + 40 +2460755.077013889 + 9 +$TDUCREATE + 40 +2458532.153996898 + 9 +$TDUPDATE + 40 +2460755.0771064814 + 9 +$TDUUPDATE + 40 +2458532.1544311 + 9 +$TDINDWG + 40 +0.0 + 9 +$TDUSRTIMER + 40 +0.0 + 9 +$USRTIMER + 70 +1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 +0 + 9 +$PDMODE + 70 +0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 +0 + 9 +$SPLINETYPE + 70 +6 + 9 +$SPLINESEGS + 70 +8 + 9 +$HANDSEED + 5 +43 + 9 +$SURFTAB1 + 70 +6 + 9 +$SURFTAB2 + 70 +6 + 9 +$SURFTYPE + 70 +6 + 9 +$SURFU + 70 +6 + 9 +$SURFV + 70 +6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 +0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 +0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 +0 + 9 +$USERI2 + 70 +0 + 9 +$USERI3 + 70 +0 + 9 +$USERI4 + 70 +0 + 9 +$USERI5 + 70 +0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 +1 + 9 +$SHADEDGE + 70 +3 + 9 +$SHADEDIF + 70 +70 + 9 +$TILEMODE + 70 +1 + 9 +$MAXACTVP + 70 +64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 +0 + 9 +$PEXTMIN + 10 +1e+20 + 20 +1e+20 + 30 +1e+20 + 9 +$PEXTMAX + 10 +-1e+20 + 20 +-1e+20 + 30 +-1e+20 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +420.0 + 20 +297.0 + 9 +$UNITMODE + 70 +0 + 9 +$VISRETAIN + 70 +1 + 9 +$PLINEGEN + 70 +0 + 9 +$PSLTSCALE + 70 +1 + 9 +$TREEDEPTH + 70 +3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 +0 + 9 +$CMLSCALE + 40 +20.0 + 9 +$PROXYGRAPHICS + 70 +1 + 9 +$MEASUREMENT + 70 +1 + 9 +$CELWEIGHT +370 +-1 + 9 +$ENDCAPS +280 +0 + 9 +$JOINSTYLE +280 +0 + 9 +$LWDISPLAY +290 +0 + 9 +$INSUNITS + 70 +6 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 +1 + 9 +$CEPSNTYPE +380 +0 + 9 +$PSTYLEMODE +290 +1 + 9 +$FINGERPRINTGUID + 2 +{C9F198A6-4C92-4D3F-B8D9-FDB4E49243ED} + 9 +$VERSIONGUID + 2 +{81B85EB0-6DA2-401D-B4F0-EAEC6C295A14} + 9 +$EXTNAMES +290 +1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 +0 + 9 +$SORTENTS +280 +127 + 9 +$INDEXCTL +280 +0 + 9 +$HIDETEXT +280 +1 + 9 +$XCLIPFRAME +280 +1 + 9 +$HALOGAP +280 +0 + 9 +$OBSCOLOR + 70 +257 + 9 +$OBSLTYPE +280 +0 + 9 +$INTERSECTIONDISPLAY +280 +0 + 9 +$INTERSECTIONCOLOR + 70 +257 + 9 +$DIMASSOC +280 +2 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 +0 + 9 +$LENSLENGTH + 40 +50.0 + 9 +$CAMERAHEIGHT + 40 +0.0 + 9 +$STEPSPERSEC + 40 +24.0 + 9 +$STEPSIZE + 40 +100.0 + 9 +$3DDWFPREC + 40 +2.0 + 9 +$PSOLWIDTH + 40 +0.005 + 9 +$PSOLHEIGHT + 40 +0.08 + 9 +$LOFTANG1 + 40 +1.570796326795 + 9 +$LOFTANG2 + 40 +1.570796326795 + 9 +$LOFTMAG1 + 40 +0.0 + 9 +$LOFTMAG2 + 40 +0.0 + 9 +$LOFTPARAM + 70 +7 + 9 +$LOFTNORMALS +280 +1 + 9 +$LATITUDE + 40 +37.795 + 9 +$LONGITUDE + 40 +-122.394 + 9 +$NORTHDIRECTION + 40 +0.0 + 9 +$TIMEZONE + 70 +-8000 + 9 +$LIGHTGLYPHDISPLAY +280 +1 + 9 +$TILEMODELIGHTSYNCH +280 +1 + 9 +$CMATERIAL +347 +20 + 9 +$SOLIDHIST +280 +0 + 9 +$SHOWHIST +280 +1 + 9 +$DWFFRAME +280 +2 + 9 +$DGNFRAME +280 +2 + 9 +$REALWORLDSCALE +290 +1 + 9 +$INTERFERECOLOR + 62 +256 + 9 +$CSHADOW +280 +0 + 9 +$SHADOWPLANELOCATION + 40 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +SUN + 2 +AcDbSun + 3 +SCENEOE + 90 +1153 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 +4095 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 +1153 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 +1153 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 +4095 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +MLEADERSTYLE + 2 +AcDbMLeaderStyle + 3 +ACDB_MLEADERSTYLE_CLASS + 90 +4095 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +CELLSTYLEMAP + 2 +AcDbCellStyleMap + 3 +ObjectDBX Classes + 90 +1152 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +MENTALRAYRENDERSETTINGS + 2 +AcDbMentalRayRenderSettings + 3 +SCENEOE + 90 +1024 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +ACDBDETAILVIEWSTYLE + 2 +AcDbDetailViewStyle + 3 +ObjectDBX Classes + 90 +1025 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +ACDBSECTIONVIEWSTYLE + 2 +AcDbSectionViewStyle + 3 +ObjectDBX Classes + 90 +1025 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +RASTERVARIABLES + 2 +AcDbRasterVariables + 3 +ISM + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +LAYOUT + 2 +AcDbLayout + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +CLASS + 1 +ACDBPLACEHOLDER + 2 +AcDbPlaceHolder + 3 +ObjectDBX Classes + 90 +0 + 91 +0 +280 +0 +281 +0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 +1 + 0 +VPORT + 5 +23 +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 +0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +0.0 + 22 +0.0 + 13 +0.0 + 23 +0.0 + 14 +0.5 + 24 +0.5 + 15 +0.5 + 25 +0.5 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +1000.0 + 41 +1.34 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 +0 + 72 +1000 + 73 +1 + 74 +3 + 75 +0 + 76 +0 + 77 +0 + 78 +0 +281 +0 + 65 +0 +146 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +2 +330 +0 +100 +AcDbSymbolTable + 70 +3 + 0 +LTYPE + 5 +24 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +25 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +26 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 +2 + 0 +LAYER + 5 +27 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 +0 + 62 +7 + 6 +Continuous +370 +-3 +390 +13 +347 +21 + 0 +LAYER + 5 +28 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Defpoints + 70 +0 + 62 +7 + 6 +Continuous +290 +0 +370 +-3 +390 +13 +347 +21 + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 +1 + 0 +STYLE + 5 +29 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 +0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 +0 + 42 +2.5 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 +3 + 0 +APPID + 5 +2A +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 +0 + 0 +APPID + 5 +40 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +HATCHBACKGROUNDCOLOR + 70 +0 + 0 +APPID + 5 +41 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +EZDXF + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +4 +330 +0 +100 +AcDbSymbolTable + 70 +1 +100 +AcDbDimStyleTable + 0 +DIMSTYLE +105 +2B +330 +4 +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 +0 + 40 +1.0 + 41 +2.5 + 42 +0.625 + 43 +3.75 + 44 +1.25 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +2.5 +140 +2.5 +141 +2.5 +142 +0.0 +143 +0.03937007874 +144 +1.0 +145 +0.0 +146 +1.0 +147 +0.625 +148 +0.0 + 69 +0 + 70 +0 + 71 +0 + 72 +0 + 73 +0 + 74 +0 + 75 +0 + 76 +0 + 77 +1 + 78 +8 + 79 +3 +170 +0 +171 +3 +172 +1 +173 +0 +174 +0 +175 +0 +176 +0 +177 +0 +178 +0 +179 +2 +271 +2 +272 +2 +273 +2 +274 +3 +275 +0 +276 +0 +277 +2 +278 +44 +279 +0 +280 +0 +281 +0 +282 +0 +283 +0 +284 +8 +285 +0 +286 +0 +288 +0 +289 +3 +290 +0 +371 +-2 +372 +-2 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 +2 + 0 +BLOCK_RECORD + 5 +17 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +1A + 70 +0 +280 +1 +281 +0 + 0 +BLOCK_RECORD + 5 +1B +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +1E + 70 +0 +280 +1 +281 +0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +18 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +19 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +1C +330 +1B +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +1D +330 +1B +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LWPOLYLINE + 5 +2F +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbPolyline + 90 +5 + 70 +1 + 10 +0.0 + 20 +0.0 + 10 +90.0 + 20 +0.0 + 10 +90.0 + 20 +100.0 + 10 +0.0 + 20 +100.0 + 10 +0.0 + 20 +0.0 + 0 +CIRCLE + 5 +30 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +40.0 + 20 +20.0 + 30 +0.0 + 40 +10.0 + 0 +CIRCLE + 5 +31 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +65.0 + 20 +20.0 + 30 +0.0 + 40 +10.0 + 0 +CIRCLE + 5 +32 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +40.0 + 20 +50.0 + 30 +0.0 + 40 +10.0 + 0 +CIRCLE + 5 +33 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +65.0 + 20 +50.0 + 30 +0.0 + 40 +10.0 + 0 +CIRCLE + 5 +34 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +40.0 + 20 +80.0 + 30 +0.0 + 40 +10.0 + 0 +CIRCLE + 5 +35 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbCircle + 10 +65.0 + 20 +80.0 + 30 +0.0 + 40 +10.0 + 0 +DIMENSION + 5 +36 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +110.0 + 20 +35.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +100.0 + 23 +50.0 + 33 +0.0 + 14 +100.0 + 24 +20.0 + 34 +0.0 + 50 +90.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +37 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +115.0 + 20 +35.0 + 30 +0.0 + 40 +2.5 + 1 +pitch +100 +AcDbText + 0 +DIMENSION + 5 +38 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +110.0 + 20 +10.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +100.0 + 23 +0.0 + 33 +0.0 + 14 +100.0 + 24 +20.0 + 34 +0.0 + 50 +90.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +39 +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +115.0 + 20 +10.0 + 30 +0.0 + 40 +2.5 + 1 +end dist. +100 +AcDbText + 0 +DIMENSION + 5 +3A +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +20.0 + 20 +-20.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +0.0 + 23 +-10.0 + 33 +0.0 + 14 +40.0 + 24 +-10.0 + 34 +0.0 + 50 +0.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +3B +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +20.0 + 20 +-25.0 + 30 +0.0 + 40 +2.5 + 1 +gauge₁ +100 +AcDbText + 0 +DIMENSION + 5 +3C +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +52.5 + 20 +-20.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +40.0 + 23 +-10.0 + 33 +0.0 + 14 +65.0 + 24 +-10.0 + 34 +0.0 + 50 +0.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +3D +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +52.5 + 20 +-25.0 + 30 +0.0 + 40 +2.5 + 1 +gauge₂ +100 +AcDbText + 0 +DIMENSION + 5 +3E +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbDimension +280 +0 + 3 +STANDARD + 10 +77.5 + 20 +-20.0 + 30 +0.0 + 70 +32 + 71 +5 + 1 +<> +100 +AcDbAlignedDimension + 13 +65.0 + 23 +-10.0 + 33 +0.0 + 14 +90.0 + 24 +-10.0 + 34 +0.0 + 50 +0.0 +100 +AcDbRotatedDimension + 0 +TEXT + 5 +3F +330 +17 +100 +AcDbEntity + 8 +0 +100 +AcDbText + 10 +77.5 + 20 +-25.0 + 30 +0.0 + 40 +2.5 + 1 +edge dist. +100 +AcDbText + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +A +330 +0 +100 +AcDbDictionary +280 +0 +281 +1 + 3 +ACAD_COLOR +350 +B + 3 +ACAD_GROUP +350 +C + 3 +ACAD_LAYOUT +350 +D + 3 +ACAD_MATERIAL +350 +E + 3 +ACAD_MLEADERSTYLE +350 +F + 3 +ACAD_MLINESTYLE +350 +10 + 3 +ACAD_PLOTSETTINGS +350 +11 + 3 +ACAD_PLOTSTYLENAME +350 +12 + 3 +ACAD_SCALELIST +350 +14 + 3 +ACAD_TABLESTYLE +350 +15 + 3 +ACAD_VISUALSTYLE +350 +16 + 3 +EZDXF_META +350 +2D + 0 +DICTIONARY + 5 +B +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +C +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +D +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Model +350 +1A + 3 +Layout1 +350 +1E + 0 +DICTIONARY + 5 +E +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +ByBlock +350 +1F + 3 +ByLayer +350 +20 + 3 +Global +350 +21 + 0 +DICTIONARY + 5 +F +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Standard +350 +2C + 0 +DICTIONARY + 5 +10 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Standard +350 +22 + 0 +DICTIONARY + 5 +11 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +ACDBDICTIONARYWDFLT + 5 +12 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Normal +350 +13 +100 +AcDbDictionaryWithDefault +340 +13 + 0 +ACDBPLACEHOLDER + 5 +13 +330 +12 + 0 +DICTIONARY + 5 +14 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +15 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +16 +330 +A +100 +AcDbDictionary +280 +0 +281 +1 + 0 +LAYOUT + 5 +1A +330 +D +100 +AcDbPlotSettings + 1 + + 4 +A3 + 6 + + 40 +7.5 + 41 +20.0 + 42 +7.5 + 43 +20.0 + 44 +420.0 + 45 +297.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +1024 + 72 +1 + 73 +0 + 74 +5 + 7 + + 75 +16 + 76 +0 + 77 +2 + 78 +300 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Model + 70 +1 + 71 +0 + 10 +0.0 + 20 +0.0 + 11 +420.0 + 21 +297.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +1e+20 + 24 +1e+20 + 34 +1e+20 + 15 +-1e+20 + 25 +-1e+20 + 35 +-1e+20 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +1 +330 +17 + 0 +LAYOUT + 5 +1E +330 +D +100 +AcDbPlotSettings + 1 + + 4 +A3 + 6 + + 40 +7.5 + 41 +20.0 + 42 +7.5 + 43 +20.0 + 44 +420.0 + 45 +297.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +0 + 72 +1 + 73 +0 + 74 +5 + 7 + + 75 +16 + 76 +0 + 77 +2 + 78 +300 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout1 + 70 +1 + 71 +1 + 10 +0.0 + 20 +0.0 + 11 +420.0 + 21 +297.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +1e+20 + 24 +1e+20 + 34 +1e+20 + 15 +-1e+20 + 25 +-1e+20 + 35 +-1e+20 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +1 +330 +1B + 0 +MATERIAL + 5 +1F +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E +100 +AcDbMaterial + 1 +ByBlock + 2 + + 70 +0 + 40 +1.0 + 71 +1 + 41 +1.0 + 91 +-1023410177 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 44 +0.5 + 73 +0 + 45 +1.0 + 46 +1.0 + 77 +1 + 4 + + 78 +1 + 79 +1 +170 +1 + 48 +1.0 +171 +1 + 6 + +172 +1 +173 +1 +174 +1 +140 +1.0 +141 +1.0 +175 +1 + 7 + +176 +1 +177 +1 +178 +1 +143 +1.0 +179 +1 + 8 + +270 +1 +271 +1 +272 +1 +145 +1.0 +146 +1.0 +273 +1 + 9 + +274 +1 +275 +1 +276 +1 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 94 +63 + 0 +MATERIAL + 5 +20 +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E +100 +AcDbMaterial + 1 +ByLayer + 2 + + 70 +0 + 40 +1.0 + 71 +1 + 41 +1.0 + 91 +-1023410177 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 44 +0.5 + 73 +0 + 45 +1.0 + 46 +1.0 + 77 +1 + 4 + + 78 +1 + 79 +1 +170 +1 + 48 +1.0 +171 +1 + 6 + +172 +1 +173 +1 +174 +1 +140 +1.0 +141 +1.0 +175 +1 + 7 + +176 +1 +177 +1 +178 +1 +143 +1.0 +179 +1 + 8 + +270 +1 +271 +1 +272 +1 +145 +1.0 +146 +1.0 +273 +1 + 9 + +274 +1 +275 +1 +276 +1 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 94 +63 + 0 +MATERIAL + 5 +21 +102 +{ACAD_REACTORS +330 +E +102 +} +330 +E +100 +AcDbMaterial + 1 +Global + 2 + + 70 +0 + 40 +1.0 + 71 +1 + 41 +1.0 + 91 +-1023410177 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 44 +0.5 + 73 +0 + 45 +1.0 + 46 +1.0 + 77 +1 + 4 + + 78 +1 + 79 +1 +170 +1 + 48 +1.0 +171 +1 + 6 + +172 +1 +173 +1 +174 +1 +140 +1.0 +141 +1.0 +175 +1 + 7 + +176 +1 +177 +1 +178 +1 +143 +1.0 +179 +1 + 8 + +270 +1 +271 +1 +272 +1 +145 +1.0 +146 +1.0 +273 +1 + 9 + +274 +1 +275 +1 +276 +1 + 42 +1.0 + 72 +1 + 3 + + 73 +1 + 74 +1 + 75 +1 + 94 +63 + 0 +MLINESTYLE + 5 +22 +102 +{ACAD_REACTORS +330 +10 +102 +} +330 +10 +100 +AcDbMlineStyle + 2 +Standard + 70 +0 + 3 + + 62 +256 + 51 +90.0 + 52 +90.0 + 71 +2 + 49 +0.5 + 62 +256 + 6 +BYLAYER + 49 +-0.5 + 62 +256 + 6 +BYLAYER + 0 +MLEADERSTYLE + 5 +2C +102 +{ACAD_REACTORS +330 +F +102 +} +330 +F +100 +AcDbMLeaderStyle +179 +2 +170 +2 +171 +1 +172 +0 + 90 +2 + 40 +0.0 + 41 +0.0 +173 +1 + 91 +-1056964608 + 92 +-2 +290 +1 + 42 +2.0 +291 +1 + 43 +8.0 + 3 +Standard + 44 +4.0 +300 + +342 +29 +174 +1 +175 +1 +176 +0 +178 +1 + 93 +-1056964608 + 45 +4.0 +292 +0 +297 +0 + 46 +4.0 + 94 +-1056964608 + 47 +1.0 + 49 +1.0 +140 +1.0 +294 +1 +141 +0.0 +177 +0 +142 +1.0 +295 +0 +296 +0 +143 +3.75 +271 +0 +272 +9 +273 +9 + 0 +DICTIONARY + 5 +2D +330 +A +100 +AcDbDictionary +280 +1 +281 +1 + 3 +CREATED_BY_EZDXF +350 +2E + 3 +WRITTEN_BY_EZDXF +350 +42 + 0 +DICTIONARYVAR + 5 +2E +330 +2D +100 +DictionaryVariables +280 +0 + 1 +1.4.0 @ 2025-03-19T20:20:54.245129+00:00 + 0 +DICTIONARYVAR + 5 +42 +330 +2D +100 +DictionaryVariables +280 +0 + 1 +1.4.0 @ 2025-03-19T20:21:02.711883+00:00 + 0 +ENDSEC + 0 +EOF diff --git a/src/flamegraph.svg b/src/flamegraph.svg new file mode 100644 index 000000000..e69de29bb diff --git a/src/osdag/Common.py b/src/osdag/Common.py index bd5c20630..99e1eb3df 100644 --- a/src/osdag/Common.py +++ b/src/osdag/Common.py @@ -422,9 +422,9 @@ def is_valid_custom(self): KEY_SR_FACTOR_YY = 'MinorSRF' KEY_DISP_SR_FACTOR_YY = 'Stress Reduction Factor' KEY_NON_DIM_ESR_ZZ = 'MajorNDESR' -KEY_DISP_NON_DIM_ESR_ZZ = 'Non-dimensional Effective SR' +KEY_DISP_NON_DIM_ESR_ZZ = 'Non-dimensional Effective SR (z-z)' KEY_NON_DIM_ESR_YY = 'MinorNDESR' -KEY_DISP_NON_DIM_ESR_YY = 'Non-dimensional Effective SR' +KEY_DISP_NON_DIM_ESR_YY = 'Non-dimensional Effective SR (y-y)' KEY_EFF_SEC_AREA_ZZ = 'MajorEffSecArea' KEY_DISP_EFF_SEC_AREA_ZZ = 'Effective Sectional Area (mm2)' KEY_EFF_SEC_AREA_YY = 'MinorEffSecArea' @@ -440,11 +440,23 @@ def is_valid_custom(self): ##Strut Design ################################### KEY_SHEAR_STRENGTH = 'Shear.Strength' +KEY_SHEAR_STRENGTH_YY = 'Shear.Strength_YY' +KEY_SHEAR_STRENGTH_ZZ = 'Shear.Strength_ZZ' KEY_MOMENT_STRENGTH = 'Moment.Strength' +KEY_MOMENT_STRENGTH_YY = 'Moment.Strength_YY' +KEY_MOMENT_STRENGTH_ZZ = 'Moment.Strength_ZZ' KEY_DISP_HIGH_SHEAR= 'High Shear Check' +KEY_DISP_HIGH_SHEAR_YY= 'High Shear Check (y-y)' +KEY_DISP_HIGH_SHEAR_ZZ= 'High Shear Check (z-z)' KEY_HIGH_SHEAR = 'Shear.High' +KEY_HIGH_SHEAR_YY = 'Shear.High_YY' +KEY_HIGH_SHEAR_ZZ = 'Shear.High_ZZ' KEY_DISP_DESIGN_STRENGTH_SHEAR = 'Shear Strength (kN)' # Design -KEY_DISP_DESIGN_STRENGTH_MOMENT = 'Moment Strength (kNm)' # Design +KEY_DISP_DESIGN_STRENGTH_SHEAR_YY = 'Shear Strength (y-y) (kN)' +KEY_DISP_DESIGN_STRENGTH_SHEAR_ZZ = 'Shear Strength (z-z) (kN)' +KEY_DISP_DESIGN_STRENGTH_MOMENT = 'Moment Strength (kNm)' # Design +KEY_DISP_DESIGN_STRENGTH_MOMENT_YY = 'Moment Strength (y-y) (kNm)' +KEY_DISP_DESIGN_STRENGTH_MOMENT_ZZ = 'Moment Strength (z-z) (kNm)' KEY_DISP_REDUCE_STRENGTH_MOMENT = 'Reduced Moment Strength (kNm)' KEY_EULER_BUCKLING_STRESS = 'MajorBucklingStress' KEY_DISP_EULER_BUCKLING_STRESS = 'Buckling Stress (MPa)' # Euler @@ -529,6 +541,7 @@ def is_valid_custom(self): KEY_DISP_FLEXURE = 'Flexural Members - Simply Supported' KEY_DISP_FLEXURE2 = 'Flexural Members - Cantilever' KEY_DISP_FLEXURE3 = 'Flexural Members' +KEY_DISP_FLEXURE4 = 'Flexural Members - Purlins' KEY_DISP_PLASTIC_STRENGTH_MOMENT = 'Plastic Strength (kNm)' KEY_DISP_Bending_STRENGTH_MOMENT = 'Bending Strength (kNm)' @@ -541,12 +554,16 @@ def is_valid_custom(self): KEY_WEB_CRIPPLING= 'Crippling.Strength' KEY_DISP_CRIPPLING_STRENGTH = 'Crippling Strength (kN)' KEY_DISP_LTB= 'Lateral Torsional Buckling Details' -KEY_DISP_Elastic_CM= 'Critical Moment (Mcr)' # Elastic -KEY_DISP_Elastic_CM_latex= 'Elastic Critical Moment(kNm)' # +KEY_DISP_Elastic_CM= 'Critical Moment (Mcr)'# Elastic +KEY_DISP_Elastic_CM_YY= 'Critical Moment (y-y) (Mcr)' +KEY_DISP_Elastic_CM_ZZ= 'Critical Moment (z-z) (Mcr)' +KEY_DISP_Elastic_CM_latex= 'Elastic Critical Moment(kNm)' # KEY_DISP_T_constatnt= 'Torsional Constant (mm4)' # (It) KEY_DISP_W_constatnt= 'Warping Constant (mm6)' # (Iw) KEY_LTB= 'L.T.B.Details' KEY_Elastic_CM= 'Elastic.Moment' +KEY_Elastic_CM_YY = 'Elastic.Moment_YY' +KEY_Elastic_CM_ZZ = 'Elastic.Moment_ZZ' KEY_T_constatnt= 'T.Constant' KEY_W_constatnt= 'W.Constant' KEY_IMPERFECTION_FACTOR_LTB = 'Imperfection.LTB' @@ -554,15 +571,34 @@ def is_valid_custom(self): KEY_NON_DIM_ESR_LTB = 'NDESR.LTB' # KEY_LTB= 'Lateral Torsional Buckling Details' KEY_WEB_BUCKLING= 'Web Buckling Details' +KEY_WEB_RESISTANCE= 'Web Resistance Details' KEY_BEARING_LENGTH = 'Bearing.Length' Simply_Supported_img = str(files("osdag.data.ResourceFiles.images").joinpath("ss_beam.png")) Cantilever_img = str(files("osdag.data.ResourceFiles.images").joinpath("c_beam.png")) +Purlin_img = str(files("osdag.data.ResourceFiles.images").joinpath("purlin.jpg")) KEY_LENGTH_OVERWRITE = 'Length.Overwrite' KEY_DISPP_LENGTH_OVERWRITE = 'Effective Length Parameter' KEY_DISP_BEAM_MOMENT = 'Bending Moment (kNm)(Mz-z)' KEY_DISP_BEAM_MOMENT_Latex = 'Bending Moment (kNm)' # ($M_{z-z}$) KEY_SUPP_TYPE = 'Member.Type' DISP_TITLE_ISECTION = 'I Sections' +KEY_DISP_CLADDING = 'Cladding (For Deflection)' + +#Web Resistance Values +KEY_BENDING_COMPRESSIVE_STRESS_YY = 'Resistance.Bending_Cmp_Stress_yy' +KEY_BENDING_COMPRESSIVE_STRESS_ZZ = 'Resistance.Bending_Cmp_Stress_zz' +KEY_DISP_BENDING_COMPRESSIVE_STRESS_YY = 'Bending Compressive Stress (y-y)' +KEY_DISP_BENDING_COMPRESSIVE_STRESS_ZZ = 'Bending Compressive Stress (z-z)' +KEY_BENDING_STRESS_RF_YY = 'Resistance.Bending_Stress_RF_yy' +KEY_BENDING_STRESS_RF_ZZ = 'Resistance.Bending_Stress_RF_zz' +KEY_DISP_BENDING_STRESS_RF_YY = 'Bending Stress Reduction Factor (y-y)' +KEY_DISP_BENDING_STRESS_RF_ZZ = 'Bending Stress Reduction Factor (z-z)' +KEY_RESISTANCE_MOMENT_YY = 'Resistance.Moment_YY' +KEY_RESISTANCE_MOMENT_ZZ = 'Resistance.Moment_ZZ' +KEY_DISP_RESISTANCE_MOMENT_YY = 'Moment (y-y)' +KEY_DISP_RESISTANCE_MOMENT_ZZ = 'Moment (z-z)' +KEY_BUCKLING_CLASS = "Buckling Class" +KEY_DISP_BUCKLING_CLASS = "Buckling Class" KEY_DISP_DESIGN_TYPE_FLEXURE = 'Laterally Supported' KEY_DESIGN_TYPE_FLEXURE = 'Flexure.Type' @@ -581,9 +617,14 @@ def is_valid_custom(self): KEY_DISP_SUPPORT = 'End Conditions' KEY_DISP_SUPPORT1 = 'Simply Supported' KEY_DISP_SUPPORT2 = 'Cantilever' -KEY_DISP_SUPPORT_LIST = list((KEY_DISP_SUPPORT1, KEY_DISP_SUPPORT2)) #[KEY_DISP_SUPPORT1, KEY_DISP_SUPPORT2] +KEY_DISP_SUPPORT3 = 'Purlins' +KEY_DISP_SUPPORT_LIST = list((KEY_DISP_SUPPORT1, KEY_DISP_SUPPORT2, KEY_DISP_SUPPORT3)) #[KEY_DISP_SUPPORT1, KEY_DISP_SUPPORT2] # KEY_SUPPORT1 = 'SimpSupport.Torsional' # KEY_SUPPORT2 = 'SimpSupport.Warping' +KEY_CLADDING_TYPE1 = 'Brittle Cladding' +KEY_CLADDING_TYPE2 = 'Elastic Cladding' +KEY_CLADDING = 'Cladding.type' +VALUES_CLADDING = list((KEY_CLADDING_TYPE1, KEY_CLADDING_TYPE2)) KEY_DISP_LENGTH_BEAM = 'Effective Span (m)*' KEY_LOAD = 'Loading.Condition' KEY_DISP_LOAD = 'Loading Condition' @@ -702,8 +743,12 @@ def is_valid_custom(self): KEY_SEC_TYPE = 'Member.Type' KEY_SHEAR = 'Load.Shear' +KEY_SHEAR_YY = 'Load.Shear.YY' +KEY_SHEAR_ZZ = 'Load.Shear.ZZ' KEY_AXIAL = 'Load.Axial' KEY_MOMENT = 'Load.Moment' +KEY_MOMENT_YY = 'Load.Moment_YY' +KEY_MOMENT_ZZ = 'Load.Moment_ZZ' KEY_D = 'Bolt.Diameter' KEY_TYP = 'Bolt.Type' @@ -954,6 +999,8 @@ def is_valid_custom(self): KEY_DISP_SECBM = 'Secondary Beam *' DISP_TITLE_FSL = 'Factored Loads' KEY_DISP_MOMENT = 'Bending Moment (kNm) *' +KEY_DISP_MOMENT_ZZ = 'Bending Moment (z-z) (kNm)' +KEY_DISP_MOMENT_YY = 'Bending Moment (y-y) (kNm)' KEY_DISP_TOP_ANGLE = 'Top Angle' @@ -999,6 +1046,8 @@ def is_valid_custom(self): KEY_DISP_D = 'Diameter (mm) *' KEY_DISP_SHEAR = 'Shear Force (kN) *' +KEY_DISP_SHEAR_YY = 'Shear Force (y-y) (kN)' +KEY_DISP_SHEAR_ZZ = 'Shear Force (z-z) (kN)' KEY_DISP_AXIAL = 'Axial Force (kN)' KEY_DISP_AXIAL_STAR = 'Axial Force (kN)* ' DISP_TITLE_PLATE = 'Plate' @@ -2225,6 +2274,7 @@ def is_valid_custom(self): VALUES_SEC_PROFILE_2 = ['Angles', 'Back to Back Angles', 'Star Angles', 'Channels', 'Back to Back Channels'] #, 'Channels', 'Back to Back Channels' VALUES_SEC_PROFILE3 = ['Beams and Columns'] #,'Channels', 'Back to Back Channels' +VALUES_SEC_PROFILE4 = ['Channels'] KEY_LENZZ = 'Member.Length_zz' KEY_DISP_LENZZ = 'Length (z-z)(mm)*' diff --git a/src/osdag/_version.py b/src/osdag/_version.py index c0f2b9843..ab6e815b2 100644 --- a/src/osdag/_version.py +++ b/src/osdag/_version.py @@ -1 +1 @@ -__version__ = "2021.02.a.a12f" +__version__ = "2025.01.a.2" diff --git a/src/osdag/cad/BBCad/BBCoverPlateBoltedCAD.py b/src/osdag/cad/BBCad/BBCoverPlateBoltedCAD.py index 9ddb3c17f..85b4e8564 100644 --- a/src/osdag/cad/BBCad/BBCoverPlateBoltedCAD.py +++ b/src/osdag/cad/BBCad/BBCoverPlateBoltedCAD.py @@ -254,10 +254,25 @@ def get_nutboltmodelsAF(self): Getting the bolt arrangement of top flange and forming a group or array out of it. ''' nut_bolts = self.nut_bolt_array_AF.get_modelsAF() + if not nut_bolts: + return None + + # Use a more efficient approach to fuse multiple shapes array = nut_bolts[0] - for comp in nut_bolts: - array = BRepAlgoAPI_Fuse(comp, array).Shape() - + if len(nut_bolts) > 1: + # Create a compound first, then fuse only once + from OCC.Core.TopoDS import TopoDS_Compound + from OCC.Core.BRep import BRep_Builder + + compound = TopoDS_Compound() + builder = BRep_Builder() + builder.MakeCompound(compound) + + for comp in nut_bolts: + builder.Add(compound, comp) + + array = BRepAlgoAPI_Fuse(nut_bolts[0], compound).Shape() + return array def get_nutboltmodelsBF(self): @@ -265,26 +280,47 @@ def get_nutboltmodelsBF(self): Getting the bolt arrangement of bottom flange and forming a group or array out of it. ''' nut_bolts = self.nut_bolt_array_BF.get_modelsBF() - array = nut_bolts[0] - for comp in nut_bolts: - array = BRepAlgoAPI_Fuse(comp, array).Shape() - + if not nut_bolts: + return None + + # Use a more efficient approach to fuse multiple shapes + from OCC.Core.TopoDS import TopoDS_Compound + from OCC.Core.BRep import BRep_Builder + + compound = TopoDS_Compound() + builder = BRep_Builder() + builder.MakeCompound(compound) + + for comp in nut_bolts[1:]: # Add all but the first to compound + builder.Add(compound, comp) + + array = BRepAlgoAPI_Fuse(nut_bolts[0], compound).Shape() + return array - - def get_nutboltmodelsWeb(self): ''' Getting the bolt arrangement of web and forming a group or array out of it. ''' nut_bolts = self.nut_bolt_array_Web.get_modelsW() - array = nut_bolts[0] - for comp in nut_bolts: - array = BRepAlgoAPI_Fuse(comp, array).Shape() - + if not nut_bolts: + return None + + # Use a more efficient approach to fuse multiple shapes + from OCC.Core.TopoDS import TopoDS_Compound + from OCC.Core.BRep import BRep_Builder + + compound = TopoDS_Compound() + builder = BRep_Builder() + builder.MakeCompound(compound) + + for comp in nut_bolts[1:]: # Add all but the first to compound + builder.Add(compound, comp) + + array = BRepAlgoAPI_Fuse(nut_bolts[0], compound).Shape() + return array - - + # Below methods are for creating holes in flange and web def get_beam_models(self): ''' @@ -312,19 +348,37 @@ def get_connector_models(self): def get_models(self): ''' - Returns: Returns model related to complete model (beams, plates and bolts) - ''' - + # First collect all models + models = [] + + # Add beam models + models.append(self.beamLModel) + models.append(self.beamRModel) + + # Add plate models + models.append(self.WebPlateLeftModel) + models.append(self.WebPlateRightModel) + models.append(self.plateAbvFlangeModel) + models.append(self.plateBelwFlangeModel) + + # Add inner plate models if needed if self.flange_splice_preference != 'Outside': - return [self.beamLModel, self.beamRModel, self.WebPlateLeftModel, self.WebPlateRightModel, - self.innerplateAbvFlangeBackModel, self.innerplateAbvFlangeFrontModel, - self.innerplateBelwFlangeBackModel, self.innerplateBelwFlangeFrontModel, self.plateAbvFlangeModel, - self.plateBelwFlangeModel] + self.nut_bolt_array_AF.get_modelsAF() + self.nut_bolt_array_BF.get_modelsBF() + self.nut_bolt_array_Web.get_modelsW() - else: - return [self.beamLModel, self.beamRModel, self.WebPlateLeftModel, self.WebPlateRightModel, - self.plateAbvFlangeModel, self.plateBelwFlangeModel] + self.nut_bolt_array_AF.get_modelsAF() + self.nut_bolt_array_BF.get_modelsBF() + self.nut_bolt_array_Web.get_modelsW() + models.append(self.innerplateAbvFlangeBackModel) + models.append(self.innerplateAbvFlangeFrontModel) + models.append(self.innerplateBelwFlangeBackModel) + models.append(self.innerplateBelwFlangeFrontModel) + + # Add bolt models + models.extend(self.nut_bolt_array_AF.get_modelsAF()) + models.extend(self.nut_bolt_array_BF.get_modelsBF()) + models.extend(self.nut_bolt_array_Web.get_modelsW()) + + # Filter out None values + models = [model for model in models if model] + + return models def get_beamLModel(self): @@ -437,12 +491,21 @@ def get_flangewebplatesModel(self): WebPlateLeft = self.get_WebPlateLeftModel() WebPlateRight = self.get_WebPlateRightModel() - CAD_list = [plateAbvFlange, plateBelwFlange, WebPlateLeft, WebPlateRight] - CAD = CAD_list[0] - - for model in CAD_list[1:]: - CAD = BRepAlgoAPI_Fuse(CAD, model).Shape() - + # Create a compound of all plates + from OCC.Core.TopoDS import TopoDS_Compound + from OCC.Core.BRep import BRep_Builder + + compound = TopoDS_Compound() + builder = BRep_Builder() + builder.MakeCompound(compound) + + for model in [plateAbvFlange, plateBelwFlange, WebPlateLeft, WebPlateRight]: + if model: + builder.Add(compound, model) + + # Perform a single fuse operation + CAD = BRepAlgoAPI_Fuse(plateAbvFlange, compound).Shape() + return CAD def get_innetplatesModels(self): @@ -454,12 +517,23 @@ def get_innetplatesModels(self): plateBelwFlangeFront = self.get_innerplateBelwFlangeFront() plateBelwFlangeBack = self.get_innerplateBelwFlangeBack() - CAD_list = [plateAbvFlangeFront, plateAbvFlangeBack, plateBelwFlangeFront, plateBelwFlangeBack] - CAD = CAD_list[0] - - for model in CAD_list[1:]: - CAD = BRepAlgoAPI_Fuse(CAD, model).Shape() - + # Create a compound + from OCC.Core.TopoDS import TopoDS_Compound + from OCC.Core.BRep import BRep_Builder + + compound = TopoDS_Compound() + builder = BRep_Builder() + builder.MakeCompound(compound) + + # Add all but the first model to the compound + models = [plateAbvFlangeBack, plateBelwFlangeFront, plateBelwFlangeBack] + for model in models: + if model: + builder.Add(compound, model) + + # Perform a single fuse operation + CAD = BRepAlgoAPI_Fuse(plateAbvFlangeFront, compound).Shape() + return CAD def get_nut_bolt_arrayModels(self): @@ -468,14 +542,28 @@ def get_nut_bolt_arrayModels(self): ''' nutboltmodelsAF = self.get_nutboltmodelsAF() nutboltmodelsBF = self.get_nutboltmodelsBF() - nutboltmodelsWeb = self.get_nutboltmodelsWeb() - - CAD_list = [nutboltmodelsAF, nutboltmodelsBF, nutboltmodelsWeb] - CAD = CAD_list[0] - - for model in CAD_list[1:]: - CAD = BRepAlgoAPI_Fuse(CAD, model).Shape() - + nutboltmodelsWeb = self.get_nutboltmodelsWeb() + + if not nutboltmodelsAF or not nutboltmodelsBF or not nutboltmodelsWeb: + return None + + # Create a compound + from OCC.Core.TopoDS import TopoDS_Compound + from OCC.Core.BRep import BRep_Builder + + compound = TopoDS_Compound() + builder = BRep_Builder() + builder.MakeCompound(compound) + + # Add other models to the compound + models = [nutboltmodelsBF, nutboltmodelsWeb] + for model in models: + if model: + builder.Add(compound, model) + + # Perform a single fuse operation + CAD = BRepAlgoAPI_Fuse(nutboltmodelsAF, compound).Shape() + return CAD def get_only_beams_Models(self): diff --git a/src/osdag/cad/MomentConnections/CCSpliceCoverPlateCAD/BoltedCAD.py b/src/osdag/cad/MomentConnections/CCSpliceCoverPlateCAD/BoltedCAD.py index c6779f495..8a05dc64d 100644 --- a/src/osdag/cad/MomentConnections/CCSpliceCoverPlateCAD/BoltedCAD.py +++ b/src/osdag/cad/MomentConnections/CCSpliceCoverPlateCAD/BoltedCAD.py @@ -1,15 +1,17 @@ """ created on 14-04-2020 - +Optimized to reduce BRepAlgoAPI_Fuse and BRepAlgoAPI_Cut calls """ import numpy -from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse -from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut +from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse, BRepAlgoAPI_Cut +from OCC.Core.TopoDS import TopoDS_Shape, topods +from OCC.Core.BOPAlgo import BOPAlgo_Builder +from OCC.Core.TopTools import TopTools_ListOfShape import copy class CCSpliceCoverPlateBoltedCAD(object): - def __init__(self, C, column, flangePlate, innerFlangePlate, webPlate, nut_bolt_array_AF, nut_bolt_array_BF, nut_bolt_array_Web): + def __init__(self, C, column, flangePlate, innerFlangePlate, webPlate, nut_bolt_array_AF, nut_bolt_array_BF, nut_bolt_array_Web): self.C = C self.column = column @@ -22,7 +24,6 @@ def __init__(self, C, column, flangePlate, innerFlangePlate, webPlate, nut_bolt self.gap = float(self.C.flange_plate.gap) - self.column1 = copy.deepcopy(self.column) self.column2 = copy.deepcopy(self.column) @@ -156,14 +157,47 @@ def create_nut_bolt_array(self): return nutBoltOriginAF + def multi_fusion(self, shapes): + """ + Fuse multiple shapes using BOPAlgo_Builder instead of multiple BRepAlgoAPI_Fuse calls + """ + if not shapes: + return None + + if len(shapes) == 1: + return shapes[0] + + # Create a BOPAlgo_Builder object for multi-fusion + builder = BOPAlgo_Builder() + + # Create a TopTools_ListOfShape and add all shapes to it + shape_list = TopTools_ListOfShape() + for shape in shapes: + shape_list.Append(shape) + + # Set the shapes to be fused + builder.SetArguments(shape_list) + + # Perform the operation + builder.Perform() + + # Return the result + if not builder.HasErrors(): + print("Using BOPAlgo_Builder for multi-fusion") + return builder.Shape() + else: + print("Using Fuse") + # Fallback to traditional method if BOPAlgo_Builder fails + result = shapes[0] + for shape in shapes[1:]: + result = BRepAlgoAPI_Fuse(result, shape).Shape() + return result def get_column_models(self): """ - :return: CAD mode for the columns """ columns = BRepAlgoAPI_Fuse(self.column1Model, self.column2Model).Shape() - return columns def get_plate_models(self): @@ -178,41 +212,30 @@ def get_plate_models(self): plates_sec = [self.flangePlate1Model, self.flangePlate2Model, self.webPlate1Model, self.webPlate2Model] - plates = plates_sec[0] - - for comp in plates_sec[1:]: - plates = BRepAlgoAPI_Fuse(comp, plates).Shape() - - return plates + # Use multi-fusion instead of sequential fusing + return self.multi_fusion(plates_sec) def get_nut_bolt_models(self): """ - :return: CAD model for all nut_bolt_arrangments + :return: CAD model for all nut_bolt_arrangments """ + # Get all bolt models nut_bolts_AF = self.nut_bolt_array_AF.get_modelsAF() - array_AF = nut_bolts_AF[0] - for comp in nut_bolts_AF: - array_AF = BRepAlgoAPI_Fuse(comp, array_AF).Shape() - nut_bolts_BF = self.nut_bolt_array_BF.get_modelsBF() - array_BF = nut_bolts_BF[0] - for comp in nut_bolts_BF: - array_BF = BRepAlgoAPI_Fuse(comp, array_BF).Shape() - nut_bolts_W = self.nut_bolt_array_Web.get_modelsW() - array_W = nut_bolts_W[0] - for comp in nut_bolts_W: - array_W = BRepAlgoAPI_Fuse(comp, array_W).Shape() - - nut_bolts_array = BRepAlgoAPI_Fuse(array_AF, array_BF).Shape() - nut_bolts_array = BRepAlgoAPI_Fuse(nut_bolts_array, array_W).Shape() - - return nut_bolts_array + + # Combine all bolt models into a single list for multi-fusion + all_bolt_models = nut_bolts_AF + nut_bolts_BF + nut_bolts_W + + # Use multi-fusion to fuse all bolt models at once + return self.multi_fusion(all_bolt_models) def get_only_column_models(self): columns = self.get_column_models() nutbolt = self.get_nut_bolt_models() + # Since we can't use multi_cut with BOPAlgo_Builder directly, + # we'll use the BRepAlgoAPI_Cut but minimize the number of calls onlycolumn = BRepAlgoAPI_Cut(columns, nutbolt).Shape() return onlycolumn @@ -221,7 +244,8 @@ def get_models(self): columns = self.get_column_models() plate_conectors = self.get_plate_models() - CAD = BRepAlgoAPI_Fuse(columns, plate_conectors).Shape() + # Use multi_fusion instead of BRepAlgoAPI_Fuse + CAD = self.multi_fusion([columns, plate_conectors]) return CAD @@ -237,7 +261,7 @@ def get_models(self): import OCC.Core.V3d - from OCC.gp import gp_Pnt + from OCC.Core.gp import gp_Pnt from OCC.Display.SimpleGui import init_display display, start_display, add_menu, add_function_to_menu = init_display() @@ -277,4 +301,4 @@ def get_models(self): display.DisplayShape(nut_bolt_array, color='YELLOW', update=True) display.DisableAntiAliasing() - start_display() + start_display() \ No newline at end of file diff --git a/src/osdag/cad/common_logic.py b/src/osdag/cad/common_logic.py index 91b9c66cf..2ea1f9f70 100644 --- a/src/osdag/cad/common_logic.py +++ b/src/osdag/cad/common_logic.py @@ -26,6 +26,7 @@ from .items.circular_hollow import CircularHollow from .items.double_angles import BackToBackAnglesWithGussetsSameSide from .items.double_angles import BackToBackAnglesWithGussetsOppSide +from .items.purlin import * from .ShearConnections.FinPlate.beamWebBeamWebConnectivity import BeamWebBeamWeb as FinBeamWebBeamWeb from .ShearConnections.FinPlate.colFlangeBeamWebConnectivity import ColFlangeBeamWeb as FinColFlangeBeamWeb @@ -579,6 +580,17 @@ def create3DColFlangeBeamWeb(self): # A = CleatAngleConnection() angle = Angle(L=A.cleat.height, A=A.cleat.leg_a_length, B=A.cleat.leg_b_length, T=A.cleat.thickness, R1=A.cleat.root_radius, R2=A.cleat.toe_radius) + print("BOLT DETAILS") + print("bolt:", A.bolt) + print("bolt2:", A.bolt2) + print("spting_leg.bolts_one_line:", A.spting_leg.bolts_one_line) + print("spting_leg.bolt_line:", A.spting_leg.bolt_line) + print("total_bolts_spting:", A.total_bolts_spting) + print("get_bolt_PC:", A.get_bolt_PC) + print("bolt_values:", A.bolt_values) + print("END BOLT DETAILS") + + elif self.connection == KEY_DISP_SEATED_ANGLE: angle = Angle(L=A.seated_angle.width, A=A.seated.leg_a_length, B=A.seated.leg_b_length, T=A.seated.thickness, R1=A.seated.root_radius, R2=A.seated.toe_radius) @@ -942,6 +954,28 @@ def createBCEndPlateCAD(self): """ BCE = self.module_class + + + print("bolt_diameter_provided:", BCE.bolt_diameter_provided) + print("bolt_grade_provided:", BCE.bolt_grade_provided) + print("bolt_numbers:", BCE.bolt_numbers) + print("BCE.ep_height_provided:", BCE.ep_height_provided) + print("BCE.ep_width_provided:", BCE.ep_width_provided) + + print("BCE.edge_distance_provided:", BCE.edge_distance_provided) + print("BCE.end_distance_provided:", BCE.end_distance_provided) + print("BCE.endplate_type:", BCE.endplate_type) + print("BCE.ep_height_max:", BCE.ep_height_max) + print("BCE.epsilon_beam:", BCE.epsilon_beam) + print("BCE.plate_thickness:", BCE.plate_thickness) + + + + + + + + column_tw = float(BCE.column_tw) column_T = float(BCE.column_tf) column_d = float(BCE.column_D) @@ -1847,6 +1881,30 @@ def createCantileverBeam(self): return sec + def createPurlin(self): + + Flex = self.module_class + print(f"This is the module name {Flex}") + + Flex.section_property = Flex.section_connect_database(Flex, Flex.result_designation) + print(f"Flex.section_property.web_thickness : {Flex.section_property.web_thickness}") + print(f"Flex.section_property.flange_thickness : {Flex.section_property.flange_thickness}") + print(f"Flex.section_property.depth : {Flex.section_property.depth}") + print(f"Flex.section_property.flange_width : {Flex.section_property.flange_width}") + print(f"Flex.section_property.root_radius : {Flex.section_property.root_radius}") + print(f"Flex.section_property.toe_radius : {Flex.section_property.toe_radius}") + print(f"Flex.support : {Flex.support}") + print(dir(Flex.section_property)) + purlin=create_c_section(length = Flex.length*1000, + depth = Flex.section_property.depth, + flange_width = Flex.section_property.flange_width, + web_thickness = Flex.section_property.web_thickness, + flange_thickness = Flex.section_property.flange_thickness) + + return purlin + + + def createStrutsInTrusses(self): Col = self.module_class Col.section_property = AngleComponent(designation = Col.result_designation, material_grade = Col.material) @@ -2142,31 +2200,62 @@ def display_3DModel(self, component, bgcolor): elif self.connection == KEY_DISP_BCENDPLATE: - self.Bc = self.module_class() + self.Bc = self.module_class self.ExtObj = self.createBCEndPlateCAD() self.display.View.SetProj(OCC.Core.V3d.V3d_XnegYnegZpos) c_length = self.column_length - # Point1 = gp_Pnt(0.0, 0.0, c_length) - # DisplayMsg(self.display, Point1, self.Bc.supporting_section.designation) - b_length = self.beam_length + self.Bc.supporting_section.depth/2+100 - # Point2 = gp_Pnt(0.0,-b_length, c_length/2) - # DisplayMsg(self.display, Point2, self.Bc.supported_section.designation) + Point1 = gp_Pnt(0.0, 0.0, c_length) + DisplayMsg(self.display, Point1, self.Bc.supporting_section.designation) + + b_length = self.beam_length + self.Bc.supporting_section.depth/2 + 100 + + Point2 = gp_Pnt(0.0, -b_length, c_length/2) + DisplayMsg(self.display, Point2, self.Bc.supported_section.designation) + + Point3 = gp_Pnt(0.0, -b_length, c_length) + DisplayMsg(self.display, Point3, f"Bolt Numbers: {self.Bc.bolt_numbers}") + + # New points for bolt info + Point4 = gp_Pnt(0.0, -b_length - 100, c_length) + DisplayMsg(self.display, Point4, f"Bolt Diameter: {self.Bc.bolt_diameter_provided}") + + Point5 = gp_Pnt(0.0, -b_length - 200, c_length) + DisplayMsg(self.display, Point5, f"Bolt Grade: {self.Bc.bolt_grade_provided}") + + # Start reference point (you can adjust these values as needed) + base_x = 0.0 + base_y = -b_length - 300 # Slightly above the previous messages + base_z = c_length + + # Display endplate height + Point6 = gp_Pnt(base_x, base_y, base_z) + DisplayMsg(self.display, Point6, f"End Plate Height: {self.Bc.ep_height_provided}") + + # Move down in Z for the next message + Point7 = gp_Pnt(base_x, base_y, base_z - 100) + DisplayMsg(self.display, Point7, f"End Plate Width: {self.Bc.ep_width_provided}") + + # Move further down in Z for the last message + Point8 = gp_Pnt(base_x, base_y, base_z - 200) + DisplayMsg(self.display, Point8, f"End Plate Thickness: {self.Bc.plate_thickness}") + + # Displays the beams #TODO ANAND if component == "Column": self.display.View_Iso() osdag_display_shape(self.display, self.ExtObj.columnModel, update=True) - # Point1 = gp_Pnt(-self.Bc.supporting_section.flange_width/2, 0, c_length) - # DisplayMsg(self.display, Point1, self.Bc.supporting_section.designation) - # Point = gp_Pnt(0.0, 0.0, 10) - # DisplayMsg(self.display,Point, "Column") + Point1 = gp_Pnt(-self.Bc.supporting_section.flange_width/2, 0, c_length) + DisplayMsg(self.display, Point1, self.Bc.supporting_section.designation) + Point = gp_Pnt(0.0, 0.0, 10) + DisplayMsg(self.display,Point, "Column") elif component == "Beam": self.display.View_Iso() osdag_display_shape(self.display, self.ExtObj.beamModel, update=True, material=Graphic3d_NOM_ALUMINIUM) - # Point2 = gp_Pnt(0.0, -b_length, c_length / 2) - # DisplayMsg(self.display, Point2, self.Bc.supported_section.designation) + Point2 = gp_Pnt(0.0, -b_length, c_length / 2) + DisplayMsg(self.display, Point2, self.Bc.supported_section.designation) # , color = 'Dark Gray' elif component == "Connector": @@ -2283,6 +2372,14 @@ def display_3DModel(self, component, bgcolor): if self.component == "Model": osdag_display_shape(self.display, self.FObj, update=True) + elif self.mainmodule == 'Flexural Members - Purlins': + self.flex = self.module_class() + print(f"THIS IS SELF.MODULE_CLASS {self.flex}") + self.FObj = self.createPurlin() + + if self.component == "Model": + osdag_display_shape(self.display, self.FObj, update=True) + elif self.mainmodule == 'Struts in Trusses': self.col = self.module_class() self.ColObj = self.createStrutsInTrusses() @@ -2458,6 +2555,14 @@ def call_3DModel(self, flag, module_class): # Done self.display_3DModel("Model", "gradient_bg") else: self.display.EraseAll() + + elif self.mainmodule == 'Flexural Members - Purlins': + if flag is True: + self.FObj = self.createPurlin() + + self.display_3DModel("Model", "gradient_bg") + else: + self.display.EraseAll() elif self.mainmodule == 'Columns with known support conditions': if flag is True: diff --git a/src/osdag/cad/items/LapJointWelded.py b/src/osdag/cad/items/LapJointWelded.py new file mode 100644 index 000000000..5250f3820 --- /dev/null +++ b/src/osdag/cad/items/LapJointWelded.py @@ -0,0 +1,140 @@ +from ISection import ISection +from notch import Notch +from plate import Plate +from filletweld import FilletWeld +import sys +import math +import numpy +import time + +# OCC Imports +# from OCC.Display.backend import load_backend +# load_backend("pyside6") +from OCC.Core.gp import gp_Pnt, gp_Vec, gp_Trsf, gp_Ax1, gp_Dir, gp_Ax3 +from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakePolygon, BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform, BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakePrism +from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse, BRepAlgoAPI_Cut +from OCC.Core.BRep import BRep_Builder +from OCC.Core.TopoDS import TopoDS_Compound +from OCC.Core.AIS import AIS_Shape +from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB +from OCC.Core.Graphic3d import Graphic3d_NOM_ALUMINIUM +from OCC.Display.SimpleGui import init_display +from OCC.Core.StlAPI import StlAPI_Writer + +def translation_movement(x,y,z, model): + """ + This function is used to translate the model by a given vector + Args: + x: float + y: float + z: float + model: TopoDS_Shape + Returns: + model: TopoDS_Shape + """ + trsf = gp_Trsf() + translation_vector = gp_Vec(x, y, z) + trsf.SetTranslation(translation_vector) + model = BRepBuilderAPI_Transform(model, trsf).Shape() + return model + +def translation_rotation(angle, axis, model): + """ + This function is used to rotate the model by a given angle around a given axis + Args: + angle: float + axis: numpy array + model: TopoDS_Shape + Returns: + model: TopoDS_Shape + """ + trsf = gp_Trsf() + ax1 = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(float(axis[0]), float(axis[1]), float(axis[2]))) + trsf.SetRotation(ax1, math.radians(angle)) + model = BRepBuilderAPI_Transform(model, trsf).Shape() + return model + +def plate_model(origin, l, b, h): + """ + This function is used to create a plate model + Args: + origin: numpy array + l: float + b: float + h: float + Returns: + plate_shape: TopoDS_Shape + """ + plate_origin = origin + plate_uDir = numpy.array([0.,0.,1.]) + plate_wDir = numpy.array([0.,1.,0.]) + plate = Plate(l, b, h) + _place = plate.place(plate_origin, plate_uDir, plate_wDir) + plate_point = plate.compute_params() + plate_shape = plate.create_model() + return plate_shape + +def filletWeld_model(b, h, l): + """ + This function is used to create a fillet weld model + Args: + b: float + h: float + l: float + Returns: + prism: TopoDS_Shape + """ + origin = numpy.array([0., 0., 0.]) + uDir = numpy.array([0., 0., 1.]) + shaftDir = numpy.array([0., 1., 0.]) + FWeld = FilletWeld(b, h, l) + _place = FWeld.place(origin, uDir, shaftDir) + point = FWeld.compute_params() + prism = FWeld.create_model(0) + return prism + +#initialisation of the display method to display the 3D model +display, start_display, add_menu, add_function_to_menu = init_display() +display.set_bg_gradient_color([51, 51, 102], [150, 150, 170]) + +#input parameters +l=50 +b=40 +h=0.5 + +#calculation of the horizontal distance between the two plates +horizontal_distance = l/3 + +weld_height = h +weld_breadth = h + +print("-----------------------------------------------------------------------") +print("generating the model") +print("-----------------------------------------------------------------------") + +#creation of the plates +top_plate = plate_model(numpy.array([0, 0, 0]) , l, b, h) +bottom_plate = plate_model(numpy.array([-horizontal_distance, 0, -h]) , l, b, h) + +#fusion of the plates +lap_plate_model = BRepAlgoAPI_Fuse(bottom_plate, top_plate).Shape() + +#creation of the fillet weld model +fillet_weld_model1 = filletWeld_model(weld_height, weld_height, b) +fillet_weld_model1 = translation_rotation(90, numpy.array([0, 1, 0]), fillet_weld_model1) +fillet_weld_model1 = translation_movement((l/2)-horizontal_distance, 0, -weld_height/2, fillet_weld_model1) + +#creation of the second fillet weld model +fillet_weld_model2 = filletWeld_model(weld_height, weld_height, b) +fillet_weld_model2 = translation_rotation(-90, numpy.array([0, 1, 0]), fillet_weld_model2) +fillet_weld_model2 = translation_movement(-l/2, 0, -h/2, fillet_weld_model2) + +#fusion of the fillet weld models +weld_model = BRepAlgoAPI_Fuse(fillet_weld_model1, fillet_weld_model2).Shape() + +#displaying the model +display.DisplayShape(lap_plate_model,material=Graphic3d_NOM_ALUMINIUM, update=True) +display.DisplayShape(weld_model,color="red", update=True) + +start_display() \ No newline at end of file diff --git a/src/osdag/cad/items/purlin.py b/src/osdag/cad/items/purlin.py new file mode 100644 index 000000000..846aecea7 --- /dev/null +++ b/src/osdag/cad/items/purlin.py @@ -0,0 +1,70 @@ +from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform, BRepBuilderAPI_MakeEdge +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakePrism +from OCC.Core.gp import gp_Pnt, gp_Vec, gp_Trsf, gp_Dir, gp_Ax1, gp_Pnt +from OCC.Core.TopoDS import TopoDS_Edge +from OCC.Display.SimpleGui import init_display +import math + +def create_c_section(length=1000, depth=200, flange_width=80, web_thickness=10, flange_thickness=10): + # Create points for the C-section profile (in Y-Z plane) + points = [ + gp_Pnt(0, 0, 0), # Bottom-left corner + gp_Pnt(0, 0, depth), # Top-left corner + gp_Pnt(0, -flange_width, depth), # Top-right of upper flange + gp_Pnt(0, -flange_width, depth-flange_thickness), # Bottom-right of upper flange + gp_Pnt(0, -web_thickness, depth-flange_thickness), # Top-right of web + gp_Pnt(0, -web_thickness, flange_thickness), # Bottom-right of web + gp_Pnt(0, -flange_width, flange_thickness), # Top-right of lower flange + gp_Pnt(0, -flange_width, 0), # Bottom-right of lower flange + ] + + # Create edges + edges = [] + for i in range(len(points)-1): + edge = BRepBuilderAPI_MakeEdge(points[i], points[i+1]).Edge() + edges.append(edge) + + # Close the profile + edge = BRepBuilderAPI_MakeEdge(points[-1], points[0]).Edge() + edges.append(edge) + + # Create wire from edges + wire_builder = BRepBuilderAPI_MakeWire() + for edge in edges: + wire_builder.Add(edge) + wire = wire_builder.Wire() + + # Create face from wire + face = BRepBuilderAPI_MakeFace(wire).Face() + + # Extrude along X-axis to create the beam + vec = gp_Vec(length, 0, 0) + beam = BRepPrimAPI_MakePrism(face, vec).Shape() + + # Create and apply the rotation transformation + trsf = gp_Trsf() + rotation_axis_z = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)) + trsf.SetRotation(rotation_axis_z, math.pi/2) + beam_transformed = BRepBuilderAPI_Transform(beam, trsf).Shape() + + return beam_transformed + +def main(): + # Initialize display + display, start_display, add_menu, add_function_to_menu = init_display() + + # Create the C-section beam + beam = create_c_section() + + # Display the beam + display.DisplayShape(beam, update=True) + + # Set view + display.View_Iso() + display.FitAll() + + # Start the display + start_display() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/osdag/cut_trace_wrapper.py b/src/osdag/cut_trace_wrapper.py new file mode 100644 index 000000000..3a48834c5 --- /dev/null +++ b/src/osdag/cut_trace_wrapper.py @@ -0,0 +1,58 @@ +import sys +import os +import OCC.Core.BRepAlgoAPI +from functools import wraps + +# File to save the trace output +TRACE_OUTPUT_FILE = "trace_output_cut.txt" + +# Path to ignore (conda environment directory) +CONDA_PATH = os.getenv('CONDA_PREFIX', '') + +# Backup original function/class +original_cut_class = OCC.Core.BRepAlgoAPI.BRepAlgoAPI_Cut + +# Create a wrapper class that inherits from the original +class TracedCutClass(original_cut_class): + def __init__(self, *args, **kwargs): + # Get caller information + frame = sys._getframe(1) + function_name = frame.f_code.co_name + line_number = frame.f_lineno + file_path = frame.f_globals.get("__file__", "") + + # Ignore calls from conda environment files + if CONDA_PATH and file_path.startswith(CONDA_PATH): + super().__init__(*args, **kwargs) + return + + # Call original constructor + super().__init__(*args, **kwargs) + + # Log details + with open(TRACE_OUTPUT_FILE, "a", encoding="utf-8") as f: + f.write(f"Function Call: BRepAlgoAPI_Cut\n") + f.write(f" Called from: {function_name}, line {line_number}, file: {file_path}\n") + f.write(f" Arguments count: {len(args)}\n") + # Safely log argument types without trying to fully stringify them + arg_types = [type(arg).__name__ for arg in args] + f.write(f" Argument types: {arg_types}\n\n") + +# Replace the original class with our traced version +OCC.Core.BRepAlgoAPI.BRepAlgoAPI_Cut = TracedCutClass + +# Clear output file before starting +with open(TRACE_OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("Trace Log:\n\n") + +# Import and execute the target script +script_path = "osdag/osdagMainPage.py" # Adjust path as needed + +# Execute only if this script is run directly +if __name__ == "__main__": + with open(script_path) as f: + code = f.read() + exec(code) + + # Restore original class after execution + OCC.Core.BRepAlgoAPI.BRepAlgoAPI_Cut = original_cut_class \ No newline at end of file diff --git a/src/osdag/data/ResourceFiles/images/purlin.jpg b/src/osdag/data/ResourceFiles/images/purlin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5cc6799e2a93bccedd06889db2eaffeb750ad4c0 GIT binary patch literal 35127 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 0: + error = self.generate_missing_fields_error_string(self, missing_fields_list) + all_errors.append(error) + else: + flag = True + + if flag and flag1 and flag2 and flag3 and flag4 and flag5: + print(f"\n design_dictionary{design_dictionary}") + self.set_input_values(self, design_dictionary) + if self.design_status == False and len(self.failed_design_dict) > 0: + logger.error( + "Design Failed, Check Design Report" + ) + return # ['Design Failed, Check Design Report'] @TODO + elif self.design_status: + pass + else: + logger.error( + "Design Failed. Selender Sections Selected" + ) + return # ['Design Failed. Selender Sections Selected'] + else: + return all_errors + + def get_3d_components(self): + + components = [] + + # t3 = ('Column', self.call_3DColumn) + # components.append(t3) + + return components + + # warn if a beam of older version of IS 808 is selected + def warn_text(self): + """ give logger warning when a beam from the older version of IS 808 is selected """ + global logger + red_list = red_list_function() + + if (self.sec_profile == VALUES_SEC_PROFILE[0]) or ( + self.sec_profile == VALUES_SEC_PROFILE[1]): # Beams or Columns + for section in self.sec_list: + if section in red_list: + logger.warning( + " : You are using a section ({}) (in red color) that is not available in latest version of IS 808".format( + section)) + + # Setting inputs from the input dock GUI + def set_input_values(self, design_dictionary): + ''' + TODO + self.bending_type == KEY_DISP_BENDING1: + self.lambda_lt = self.lambda_lt_check_member_type + if self.lambda_lt < 0.4: + self.design_type == KEY_DISP_DESIGN_TYPE_FLEXURE + ''' + super(Flexure_Purlin, self).set_input_values(self, design_dictionary) + + # section properties + self.module = design_dictionary[KEY_MODULE] + self.mainmodule = KEY_DISP_FLEXURE4 + self.sec_profile = design_dictionary[KEY_SEC_PROFILE] + self.sec_list = design_dictionary[KEY_SECSIZE] + print(f"\n Inside set_input_values{self.sec_profile}") + print(f"\n sec_profile{self.sec_list}") + self.main_material = design_dictionary[KEY_MATERIAL] + self.material = design_dictionary[KEY_SEC_MATERIAL] + + # design type + ''' + Temporarily has been set to Major Laterally Supported, further on will be changed + ''' + self.design_type_temp = KEY_DISP_BENDING1 + " " + KEY_DISP_DESIGN_TYPE_FLEXURE # or KEY_DISP_DESIGN_TYPE2_FLEXURE + self.latex_design_type = KEY_DISP_BENDING1 + " " + KEY_DISP_DESIGN_TYPE_FLEXURE # or KEY_DISP_DESIGN_TYPE2_FLEXURE + if self.design_type_temp == VALUES_SUPP_TYPE_temp[0]: + self.design_type = VALUES_SUPP_TYPE[0] # or KEY_DISP_DESIGN_TYPE2_FLEXURE + self.bending_type = KEY_DISP_BENDING1 + # TODO self.support_cndition_shear_buckling + self.support_cndition_shear_buckling = 'NA' # design_dictionary[KEY_ShearBucklingOption] + elif self.design_type_temp == VALUES_SUPP_TYPE_temp[1]: + self.design_type = VALUES_SUPP_TYPE[0] + self.bending_type = KEY_DISP_BENDING2 # if design_dictionary[KEY_BENDING] != 'Disabled' else 'NA' + self.support_cndition_shear_buckling = 'NA' + + elif self.design_type_temp == VALUES_SUPP_TYPE_temp[2]: + self.design_type = VALUES_SUPP_TYPE[1] + self.bending_type = KEY_DISP_BENDING1 + self.support_cndition_shear_buckling = 'NA' + + # section user data + self.length = float(design_dictionary[KEY_LENGTH]) + + # end condition + self.support = 'Supported' + + # factored loads + self.load = Load( + shear_force_yy=design_dictionary[KEY_SHEAR_YY], + shear_force_zz=design_dictionary[KEY_SHEAR_ZZ], + axial_force="", + moment_yy=design_dictionary[KEY_MOMENT_YY], + moment_zz=design_dictionary[KEY_MOMENT_ZZ], + unit_kNm=True, + ) + + self.cladding = design_dictionary[KEY_CLADDING] + + # design preferences + # self.allowable_utilization_ratio = float(design_dictionary[KEY_ALLOW_UR]) + self.latex_efp = design_dictionary[KEY_LENGTH_OVERWRITE] + self.effective_area_factor = float(design_dictionary[KEY_EFFECTIVE_AREA_PARA]) + self.allowable_utilization_ratio = 1.0 + self.optimization_parameter = "Utilization Ratio" + self.allow_class = design_dictionary[KEY_ALLOW_CLASS] # if 'Semi-Compact' is available + self.steel_cost_per_kg = 50 + # Step 2 - computing the design compressive stress for web_buckling & web_crippling + self.bearing_length = design_dictionary[KEY_BEARING_LENGTH] + # TAKE from Design Dictionary + self.allowed_sections = [] + if self.allow_class == "Yes": + self.allowed_sections == KEY_SemiCompact + + print(f"self.allowed_sections {self.allowed_sections}") + print("==================") + # print(f"self.load_type {self.load_type}") + + print(f"self.module{self.module}") + print(f"self.sec_list {self.sec_list}") + print(f"self.material {self.material}") + print(f"self.length {self.length}") + print(f"self.load {self.load}") + print("==================") + + # safety factors + self.gamma_m0 = IS800_2007.cl_5_4_1_Table_5["gamma_m0"]["yielding"] + self.gamma_m1 = IS800_2007.cl_5_4_1_Table_5["gamma_m1"]["ultimate_stress"] + self.material_property = Material(material_grade=self.material, thickness=0) + self.fyf = self.material_property.fy + self.fyw = self.material_property.fy + + print(f"self.material_property {self.material_property}]") + # print( "self.material_property",self.material_property.fy) + # initialize the design status + self.design_status_list = [] + self.design_status = False + self.sec_prop_initial_dict = {} + self.failed_design_dict = {} + self.design(self, design_dictionary) + if self.flag: + self.results(self, design_dictionary) + + # Simulation starts here + def design(self, design_dictionary, flag=0): + ''' + TODO optimimation_tab_check changes to include self.material_property = Material(material_grade=self.material, thickness=0) + for each section + ''' + # flag = self.section_classification(self) + print(f"\n Inside design") + # self.show_error_message(self) + """Perform design of struct""" + # checking DP inputs + + self.optimization_tab_check(self) + # print( "self.material_property",self.material_property.fy) + self.input_modifier(self) + # print( "self.material_property",self.material_property.fy) + + self.design_beam(self, design_dictionary) + + def optimization_tab_check(self): + ''' + TODO add button to give user option to take Tension holes or not + ''' + print(f"\n Inside optimization_tab_check") + self.latex_tension_zone = False + if (self.effective_area_factor <= 0.10) or (self.effective_area_factor > 1.0): + logger.error( + "The defined value of Effective Area Factor in the design preferences tab is out of the suggested range." + ) + logger.info("Provide an appropriate input and re-design.") + logger.warning("Assuming a default value of 1.0.") + self.effective_area_factor = 1.0 + # self.design_status = False + # self.design_status_list.append(self.design_status) + self.optimization_tab_check(self) + elif (self.steel_cost_per_kg < 0.10) or (self.effective_area_factor > 1.0) or (self.effective_area_factor < 0): + # No suggested range in Description + logger.warning( + "The defined value of the effective area factor in the design preferences tab is out of the suggested range." + ) + logger.info("Assuming a default value of 1.0") + + self.steel_cost_per_kg = 50 + self.effective_area_factor = 1 + + self.design_status = False + # self.design_status_list.append(self.design_status) + else: + if self.latex_tension_zone: + if self.effective_area_factor >= ( + self.material_property.fy * self.gamma_m0 / (self.material_property.fu * 0.9 * self.gamma_m1)): + pass + else: + self.latex_tension_zone = True + print(f'self.latex_tension_zone: {self.latex_tension_zone}') + # self.effective_area_factor = ( + # self.material_property.fy + # * self.gamma_m0 + # / (self.material_property.fu * 0.9 * self.gamma_m1) + # ) + # logger.info( + # f"The effect of holes in the tension flange is considered on the design bending strength. The ratio of net to gross area of the flange in tension is considered {self.effective_area_factor}" + # ) + + logger.info("Provided appropriate design preference, now checking input.") + + def input_modifier(self): + """Classify the sections based on Table 2 of IS 800:2007""" + print(f"Inside input_modifier") + local_flag = True + self.input_modified = [] + self.input_section_list = [] + self.input_section_classification = {} + + for section in self.sec_list: + section = section.strip("'") + self.section_property = self.section_connect_database(self, section) + + self.Zp_req = self.load.moment * self.gamma_m0 / self.material_property.fy + print('Inside input_modifier not allow_class', self.allow_class, self.load.moment, self.gamma_m0, + self.material_property.fy) + if self.section_property.plast_sec_mod_z >= self.Zp_req: + self.input_modified.append(section) + # logger.info( + # f"Required self.Zp_req = {round(self.Zp_req * 10**-3,2)} x 10^3 mm^3 and Zp of section {self.section_property.designation} = {round(self.section_property.plast_sec_mod_z* 10**-3,2)} x 10^3 mm^3.Section satisfy Min self.Zp_req value") + # else: + # local_flag = False + + # logger.warning( + # f"Required self.Zp_req = {round(self.Zp_req* 10**-3,2)} x 10^3 mm^3 and Zp of section {self.section_property.designation} = {round(self.section_property.plast_sec_mod_z* 10**-3,2)} x 10^3 mm^3.Section dosen't satisfy Min self.Zp_req value") + print("self.input_modified", self.input_modified) + + def section_connect_database(self, section): + print(f"section_connect_database{section}") + print(section) + # print(self.sec_profile) + if ( + self.sec_profile == VALUES_SECTYPE[1] + or self.sec_profile == "I-section" + ): # I-section + self.section_property = ISection( + designation=section, material_grade=self.material + ) + print(self.section_property) + self.material_property.connect_to_database_to_get_fy_fu( + self.material, max(self.section_property.flange_thickness, self.section_property.web_thickness) + ) + print(f"section_connect_database material_property.fy{self.material_property.fy}") + self.epsilon = math.sqrt(250 / self.material_property.fy) + elif (self.sec_profile == VALUES_SECTYPE[6]): + print(self.material) + self.section_property = ISection( + designation=section, material_grade=self.material, table=self.sec_profile + ) + print(self.section_property) + self.material_property.connect_to_database_to_get_fy_fu( + self.material, max(self.section_property.flange_thickness, self.section_property.web_thickness) + ) + print(f"section_connect_database material_property.fy{self.material_property.fy}") + self.epsilon = math.sqrt(250 / self.material_property.fy) + + return self.section_property + + def design_beam(self, design_dictionary): + print(f"Inside design_beam") + # 1- Based on optimum UR + self.optimum_section_ur_results = {} + self.optimum_section_ur = [] + + # 2 - Based on optimum cost + self.optimum_section_cost_results = {} + self.optimum_section_cost = [] + + # 1 - section classification + self.flag = self.section_classification(self, design_dictionary) + + print('self.flag:', self.flag) + if self.effective_area_factor < 1.0: + logger.warning( + "Reducing the effective sectional area as per the definition in the Design Preferences tab." + ) + else: + logger.info( + "The effective sectional area is taken as 100% of the cross-sectional area [Reference: Cl. 7.3.2, IS 800:2007]." + ) + print( + f"self.effective_length {self.effective_length} \n self.input_section_classification{self.input_section_classification} ") + + if self.flag: + for section in self.input_section_list: + # initialize lists for updating the results dictionary + self.section_property = self.section_connect_database(self, section) + if self.section_property.type == 'Rolled': + self.effective_depth = (self.section_property.depth - 2 * ( + self.section_property.flange_thickness + self.section_property.root_radius)) + else: + self.effective_depth = (self.section_property.depth - 2 * self.section_property.flange_thickness) + print('self.section_property.type:', self.section_property.type, self.bending_type) + + # Step 1.1 - computing the effective sectional area + self.effective_area = self.section_property.area + + list_result = [] + list_1 = [] + list_result.append(section) + list_1.append("Designation") + self.section_class = self.input_section_classification[section][0] + self.It = self.input_section_classification[section][5] + self.hf = self.input_section_classification[section][6] + self.Iw = self.input_section_classification[section][7] + # 2.9 - Cost of the section in INR + self.depth_thickness_ratio = self.effective_depth / self.section_property.web_thickness + self.web_buckling_check = IS800_2007.cl_8_2_1_web_buckling( + d=self.effective_depth, + tw=self.section_property.web_thickness, + e=self.epsilon, + ) + + if self.section_class == KEY_Plastic or self.section_class == KEY_Compact: + self.beta_b_lt = 1.0 + else: + self.beta_b_lt = ( + self.section_property.elast_sec_mod_z + / self.section_property.plast_sec_mod_z + ) + + if (not self.web_buckling_check): + self.shear_area_zz = self.section_property.depth * self.section_property.web_thickness + self.shear_area_yy = 2 * self.section_property.flange_width * self.section_property.flange_thickness + self.buckling_class = 'c' + print(f"shear area ZZ is {self.shear_area_zz}") + print(f"shear area YY is {self.shear_area_yy}") + self.V_d_yy = IS800_2007.cl_8_4_design_shear_strength( + self.shear_area_yy, + self.material_property.fy + ) + self.V_d_zz = IS800_2007.cl_8_4_design_shear_strength( + self.shear_area_zz, + self.material_property.fy + ) + + print(f"shear force yy is {self.load.shear_force_yy}") + print(f"shear force zz is {self.load.shear_force_zz}") + + if self.load.shear_force_yy < self.V_d_yy and self.load.shear_force_zz < self.V_d_zz: + + self.high_shear_check_yy = IS800_2007.cl_8_2_1_2_high_shear_check( + self.load.shear_force_yy, + self.V_d_yy + ) + self.high_shear_check_zz = IS800_2007.cl_8_2_1_2_high_shear_check( + self.load.shear_force_zz, + self.V_d_zz + ) + print(f"high shear check yy is {self.high_shear_check_yy}") + print(f"high shear check zz is {self.high_shear_check_zz}") + + self.M_d_yy = self.design_bending_strength_purlins( + self, + self.section_class, + self.section_property.plast_sec_mod_y, + self.section_property.elast_sec_mod_y, + self.section_property.fy, + self.gamma_m0, + self.high_shear_check_yy, + 'y' + ) + + self.M_d_zz = self.design_bending_strength_purlins( + self, + self.section_class, + self.section_property.plast_sec_mod_z, + self.section_property.elast_sec_mod_z, + self.section_property.fy, + self.gamma_m0, + self.high_shear_check_zz, + 'z' + ) + if self.load.moment_yy < self.M_d_yy and self.load.moment_zz < self.M_d_zz: + + self.M_d_yy1 = self.web_resistance_check( + self, + self.section_property.mom_inertia_y, + self.section_property.elast_sec_mod_y, + self.section_property.plast_sec_mod_y, + self.section_property.rad_of_gy_z, + 'y' + ) + + self.M_d_zz1 = self.web_resistance_check( + self, + self.section_property.mom_inertia_z, + self.section_property.elast_sec_mod_z, + self.section_property.plast_sec_mod_z, + self.section_property.rad_of_gy_y, + 'z' + ) + + self.ur = max( + self.load.shear_force_yy / self.V_d_yy, + self.load.shear_force_zz / self.V_d_zz, + self.load.moment_yy / self.M_d_yy, + self.load.moment_zz / self.M_d_zz, + (self.load.moment_yy / self.M_d_yy1) + + (self.load.moment_zz / self.M_d_zz1) + ) + self.optimum_section_ur.append(self.ur) + + self.web_buckling_check1 = self.buckling_resistance_check( + self, + self.load.moment_yy, + self.load.moment_zz, + self.M_d_yy1, + self.M_d_zz1, + ) + + if (self.web_buckling_check1): + ''' + Deflection check + ''' + w_y = (self.load.shear_force_yy ** 2) / (2 * self.load.moment_yy * 1.5) + w_z = (self.load.shear_force_zz ** 2) / (2 * self.load.moment_zz * 1.5) + del_y = self.serviceability_check(self, w_y, + self.section_property.elast_sec_mod_y, + self.section_property.mom_inertia_y + ) + del_z = self.serviceability_check(self, w_z, + self.section_property.elast_sec_mod_z, + self.section_property.mom_inertia_z + ) + + if self.cladding == 'Brittle Cladding': + del_limit = self.length / 180 + else: + del_limit = self.length / 150 + + if del_z < del_limit and del_y < del_limit: + self.cost = ( + ( + self.section_property.unit_mass + * self.section_property.area + * 1e-4 + ) + * self.length + * self.steel_cost_per_kg + ) + self.optimum_section_cost.append(self.cost) + list_result, list_1 = self.list_changer(self, + change=None, + check=True, + list=list_result, list_name=list_1) + self.common_checks_1(self, section, 5, list_result, list_1) + else: + list_1.extend(["Section class", "It", "Iw", "Web.Buckling", "Beta_b"]) + list_result.extend( + [self.section_class, self.It, self.Iw, self.web_buckling_check, self.beta_b_lt]) + self.common_checks_1(self, section, 5, list_result, list_1) + else: + list_1.extend(["Section class", "It", "Iw", "Web.Buckling", "Beta_b"]) + list_result.extend( + [self.section_class, self.It, self.Iw, self.web_buckling_check, self.beta_b_lt]) + self.common_checks_1(self, section, 5, list_result, list_1) + else: + list_1.extend(["Section class", "It", "Iw", "Web.Buckling", "Beta_b"]) + list_result.extend( + [self.section_class, self.It, self.Iw, self.web_buckling_check, self.beta_b_lt]) + self.common_checks_1(self, section, 5, list_result, list_1) + else: + list_1.extend(["Section class", "It", "Iw", "Web.Buckling", "Beta_b"]) + list_result.extend( + [self.section_class, self.It, self.Iw, self.web_buckling_check, self.beta_b_lt]) + self.common_checks_1(self, section, 5, list_result, list_1) + else: + list_1.extend(["Section class", "It", "Iw", "Web.Buckling", "Beta_b"]) + list_result.extend([self.section_class, self.It, self.Iw, self.web_buckling_check, self.beta_b_lt]) + self.common_checks_1(self, section, 5, list_result, list_1) + + ''' + if self.bearing_length != 'NA': # and self.web_crippling + print(f"Check for Web Buckling") + try: + self.bearing_length = float(design_dictionary[KEY_BEARING_LENGTH]) + self.web_buckling = True # WEB BUCKLING + self.I_eff_web = self.bearing_length * self.section_property.web_thickness ** 3 / 12 + self.A_eff_web = self.bearing_length * self.section_property.web_thickness + self.r = math.sqrt(self.I_eff_web / self.A_eff_web) + self.slenderness = 0.7 * self.effective_depth / self.r + self.common_checks_1(self, section, step=3) + # step == 4 + self.common_checks_1( + self, section, step=4, list_result=["Concentric"] + ) + # 2.7 - Capacity of the section for web_buckling + self.section_capacity = ( + self.design_compressive_stress * ( + self.bearing_length + self.section_property.depth / 2) * self.section_property.web_thickness + * 10 ** -3) # N + print(self.design_compressive_stress, self.bearing_length, self.section_property.depth, + self.section_property.web_thickness) + + print(self.bending_strength_section, self.shear_strength, self.section_capacity) + + self.F_wb = (self.bearing_length + 2.5 * ( + self.section_property.root_radius + self.section_property.flange_thickness)) * self.section_property.web_thickness * self.material_property.fy / ( + self.gamma_m0 * 10 ** 3) + if self.bending_strength_section > self.load.moment * 10 ** -6 and self.shear_strength > self.load.shear_force * 10 ** -3 and self.section_capacity > self.load.shear_force * 10 ** -3 and self.F_wb > self.load.shear_force * 10 ** -3: + list_result, list_1 = self.list_changer(self, change='Web Buckling', check=True, + list=list_result, list_name=list_1) + self.optimum_section_ur.append(self.ur) + else: + list_result, list_1 = self.list_changer(self, change='Web Buckling', check=True, + list=list_result, list_name=list_1) + self.optimum_section_ur.append(self.ur) + # Step 3 - Storing the optimum results to a list in a descending order + self.common_checks_1(self, section, 5, list_result, list_1) + except: + logger.warning('Bearing length is invalid.') + logger.info('Ignoring web Buckling and Crippling check') + self.bearing_length = 'NA' + self.web_buckling = False + # 2.8 - UR + print(self.bending_strength_section, self.shear_strength) + if self.bending_strength_section > self.load.moment * 10 ** -6 and self.shear_strength > self.load.shear_force * 10 ** -3: + list_result, list_1 = self.list_changer(self, change='', check=True, list=list_result, + list_name=list_1) + self.optimum_section_ur.append(self.ur) + + # Step 3 - Storing the optimum results to a list in a descending order + self.common_checks_1(self, section, 5, list_result, list_1) + else: + list_result, list_1 = self.list_changer(self, change='', check=True, list=list_result, + list_name=list_1) + self.optimum_section_ur.append(self.ur) + # Step 3 - Storing the optimum results to a list in a descending order + self.common_checks_1(self, section, 5, list_result, list_1) + + else: + self.web_buckling = False + # 2.8 - UR + print(self.bending_strength_section, self.shear_strength) + if self.bending_strength_section > self.load.moment * 10 ** -6 and self.shear_strength > self.load.shear_force * 10 ** -3: + + self.optimum_section_ur.append(self.ur) + list_result, list_1 = self.list_changer(self, change=' ', check=True, list=list_result, + list_name=list_1) + + # Step 3 - Storing the optimum results to a list in a descending order + self.common_checks_1(self, section, 5, list_result, list_1) + else: + self.optimum_section_ur.append(self.ur) + list_result, list_1 = self.list_changer(self, change=' ', check=True, list=list_result, + list_name=list_1) + + # Step 3 - Storing the optimum results to a list in a descending order + self.common_checks_1(self, section, 5, list_result, list_1) + ''' + print('self.optimum_section_ur', self.optimum_section_ur) + + def beam_web_buckling(self): + + print(f"Working web_buckling_check") + # 3 - web buckling under shear + self.web_buckling_check = IS800_2007.cl_8_2_1_web_buckling( + d=self.effective_depth, + tw=self.section_property.web_thickness, + e=self.epsilon, + ) + print(self.web_buckling_check, self.section_property.designation) + + if not self.web_buckling_check: + self.web_not_buckling_steps(self) + + def web_buckling_steps(self): + print(f"Not using web_buckling_steps") + # logger.info(f"Considering {self.support_cndition_shear_buckling}") + # 5 - Web Buckling check(when high shear) -If user wants then only + # if web_buckling: + # b1 = input('Enter bearing') + # self.web_buckling_strength = self.section_property.web_thickness * (b1 + 1.25 * self.section_property.depth) + # self.V_d = pass + # web_buckling_message = 'Thin web' + if self.support_cndition_shear_buckling == KEY_DISP_SB_Option[0]: + self.K_v = IS800_2007.cl_8_4_2_2_K_v_Simple_postcritical('only support') + self.plate_girder_strength(self) + # logger.info('Section = {}, V_cr = {}'.format(self.section_property.designation, round(self.V_cr,2))) + self.shear_strength = self.V_cr / self.gamma_m0 + # if self.V_d > self.load.shear_force * 10**-3: + # + # return True + # else: + # return False + # self.V_d = IS800_2007.cl_8_4_2_2_ShearBuckling_Simple_postcritical((self.section_property.depth - 2 *(self.section_property.flange_thickness + self.section_property.root_radius), + # self.section_property.web_thickness,space,0.3, self.fyw)) + elif self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1]: + self.V_p = IS800_2007.cl_8_4_design_shear_strength( + self.shear_area, + self.material_property.fy + ) / 10 ** 3 * self.gamma_m0 + self.Mfr = IS800_2007.cl_8_4_2_2_Mfr_TensionField(self.section_property.flange_width, + self.section_property.flange_thickness, self.fyf, + self.load.moment / ( + self.section_property.depth - self.section_property.flange_thickness), + self.gamma_m0) + print('MFr', self.Mfr) + if self.Mfr > 0: + print('Starting loop', int(round(self.effective_length * 10 ** 4 / self.effective_depth, -1) / 10)) + # for c_d in range(3,self.effective_length/self.result_eff_d): + for c_d in reversed( + list(range(3, int(round(self.effective_length * 1000 / self.effective_depth, -1))))): + print('c_d', c_d, 'c/d', self.effective_length * 1000 / self.effective_depth) + c_d = c_d / 10 + 0.1 + self.c = round(c_d * self.effective_depth, -1) + print('c', self.c) + self.K_v = IS800_2007.cl_8_4_2_2_K_v_Simple_postcritical('many support', self.c, + self.effective_depth) + self.plate_girder_strength2(self) + + self.shear_strength = self.V_tf_girder / self.gamma_m0 * 10 ** -3 + logger.info( + 'Intermediate Stiffeners required d ={}, c = {}, Section = {}, V_tf = {}, V_d = {}'.format( + self.effective_depth, self.c, + self.section_property.designation, + self.V_tf_girder, self.shear_strength)) + if self.shear_strength > self.load.shear_force * 10 ** -3: + return + return + else: + self.shear_strength = 0.1 + + def web_not_buckling_steps(self): + print(f"Working web_not_buckling_steps") + self.V_d = IS800_2007.cl_8_4_design_shear_strength( + self.shear_area, + self.material_property.fy + ) / 10 ** 3 + self.shear_strength = self.V_d + self.high_shear_check = IS800_2007.cl_8_2_1_2_high_shear_check( + self.load.shear_force / 1000, self.V_d + ) + print( + f"self.V_d {self.V_d},{self.section_property.depth * self.section_property.web_thickness}, {self.material_property.fy}") + # 4 - design bending strength + self.bending_strength_section = self.bending_strength(self) / 10 ** 6 + + def bending_strength(self): + print('Inside bending_strength ', '\n self.section_class', self.section_class) + # 4 - design bending strength + + if self.high_shear_check: + if self.section_class == KEY_Plastic or self.section_class == KEY_Compact: + bending_strength_section = self.bending_strength_reduction(self, M_d) + else: + bending_strength_section = ( + self.section_property.elast_sec_mod_z + * self.material_property.fy + / self.gamma_m0 + ) + else: + bending_strength_section = M_d + print('Inside bending_strength 1', M_d, self.high_shear_check, bending_strength_section) + # self.It = ( + # 2 + # * self.section_property.flange_width + # * self.section_property.flange_thickness**3 + # ) / 3 + ( + # (self.section_property.depth - self.section_property.flange_thickness) + # * self.section_property.web_thickness**3 + # ) / 3 + # self.hf = self.section_property.depth - self.section_property.flange_thickness + # self.Iw = 0.5**2 * self.section_property.mom_inertia_y * self.hf**2 + # self.M_cr = IS800_2007.cl_8_2_2_Unsupported_beam_bending_non_slenderness( + # self.material_property.modulus_of_elasticity, + # 0.3, + # self.section_property.mom_inertia_y, + # self.It, + # self.Iw, + # self.effective_length * 1e3 + # ) + # + # if self.section_class == KEY_Plastic or self.section_class == KEY_Compact: + # self.beta_b_lt = 1.0 + # else: + # self.beta_b_lt = ( + # self.section_property.elast_sec_mod_z + # / self.section_property.plast_sec_mod_z + # ) + if self.section_property.type == "Rolled": + alpha_lt = 0.21 + else: + alpha_lt = 0.49 + # lambda_lt = IS800_2007.cl_8_2_2_1_elastic_buckling_moment( + # self.beta_b_lt, + # self.section_property.plast_sec_mod_z, + # self.section_property.elast_sec_mod_z, + # self.material_property.fy, + # self.M_cr + # ) + phi_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_phi_lt( + alpha_lt, self.lambda_lt + ) + X_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_stress_reduction_factor( + phi_lt, self.lambda_lt + ) + fbd = IS800_2007.cl_8_2_2_Unsupported_beam_bending_compressive_stress( + X_lt, self.material_property.fy, self.gamma_m0 + ) + bending_strength_section = IS800_2007.cl_8_2_2_Unsupported_beam_bending_strength( + self.section_property.plast_sec_mod_z, + self.section_property.elast_sec_mod_z, + fcd=fbd, + section_class=self.section_class + ) + # self.beta_b_lt = beta_b + self.alpha_lt = alpha_lt + # self.lambda_lt = lambda_lt + self.phi_lt = phi_lt + self.X_lt = X_lt + self.fbd_lt = fbd + self.lateral_tb = self.M_cr * 10 ** -6 + print('Inside bending_strength 2.1', fbd, self.section_property.plast_sec_mod_z) + if self.high_shear_check: + if self.section_class == KEY_Plastic or self.section_class == KEY_Compact: + bending_strength_section = self.bending_strength_reduction(self, Md=bending_strength_section + ) + else: + bending_strength_section = ( + self.beta_b_lt + * self.section_property.plast_sec_mod_z + * fbd + ) + print('Inside bending_strength 2', self.It, self.hf, self.Iw, self.M_cr, self.beta_b_lt, alpha_lt, + self.lambda_lt, phi_lt, X_lt, fbd, bending_strength_section) + self.bending_strength_section_reduced = bending_strength_section + return bending_strength_section + + def bending_strength_girder(self): + print('Inside bending_strength of girder ') + web_class = IS800_2007.Table2_i( + (self.section_property.flange_width - self.section_property.web_thickness) / 2, + self.section_property.flange_thickness, + self.material_property.fy, self.section_property.type + )[0] + flange_class = IS800_2007.Table2_i( + self.section_property.depth - 2 * self.section_property.flange_thickness, + self.section_property.web_thickness, + self.material_property.fy, self.section_property.type + )[0] + if flange_class == "Slender" or web_class == "Slender": + self.section_class_girder = "Slender" + else: + if flange_class == KEY_Plastic and web_class == KEY_Plastic: + self.section_class_girder = KEY_Plastic + elif flange_class == KEY_Plastic and web_class == KEY_Compact: + self.section_class_girder = KEY_Compact + elif flange_class == KEY_Plastic and web_class == KEY_SemiCompact: + self.section_class_girder = KEY_SemiCompact + elif flange_class == KEY_Compact and web_class == KEY_Plastic: + self.section_class_girder = KEY_Compact + elif flange_class == KEY_Compact and web_class == KEY_Compact: + self.section_class_girder = KEY_Compact + elif flange_class == KEY_Compact and web_class == KEY_SemiCompact: + self.section_class_girder = KEY_SemiCompact + elif flange_class == KEY_SemiCompact and web_class == KEY_Plastic: + self.section_class_girder = KEY_SemiCompact + elif flange_class == KEY_SemiCompact and web_class == KEY_Compact: + self.section_class_girder = KEY_SemiCompact + elif flange_class == KEY_SemiCompact and web_class == KEY_SemiCompact: + self.section_class_girder = KEY_SemiCompact + # 4 - design bending strength + I_flange = 2 * ( + self.section_property.flange_width * self.section_property.flange_thickness ** 3 / 12 + self.section_property.flange_width * self.section_property.flange_thickness * ( + self.section_property.depth / 2 - self.section_property.flange_thickness / 2) ** 2) + Zez_flange = I_flange / self.section_property.depth / 2 + y_top = (self.section_property.flange_width * self.section_property.flange_thickness * ( + self.section_property.depth - self.section_property.flange_thickness) / 2) / ( + self.section_property.flange_width * self.section_property.flange_thickness) + Zpz_flange = 2 * self.section_property.flange_width * self.section_property.flange_thickness * y_top + M_d = IS800_2007.cl_8_2_1_2_design_bending_strength( + self.section_class_girder, + Zpz_flange, + Zez_flange, + self.material_property.fy, + self.gamma_m0, + self.support, + ) + if self.section_class_girder == KEY_Plastic or self.section_class_girder == KEY_Compact: + self.beta_b_lt = 1 + else: + self.beta_b_lt = Zez_flange / Zpz_flange + self.M_d = M_d + if self.design_type == KEY_DISP_DESIGN_TYPE_FLEXURE: + if self.high_shear_check: + if self.section_class_girder == KEY_Plastic or self.section_class_girder == KEY_Compact: + bending_strength_section = self.bending_strength_reduction(self, M_d) + else: + bending_strength_section = ( + self.section_property.elast_sec_mod_z + * self.material_property.fy + / self.gamma_m0 + ) + else: + bending_strength_section = M_d + print('Inside bending_strength 1', M_d, self.high_shear_check, bending_strength_section) + else: + # self.It = ( + # 2 + # * self.section_property.flange_width + # * self.section_property.flange_thickness**3 + # ) / 3 + ( + # (self.section_property.depth - self.section_property.flange_thickness) + # * self.section_property.web_thickness**3 + # ) / 3 + self.hf = self.section_property.depth - self.section_property.flange_thickness + # self.Iw = 0.5**2 * self.section_property.mom_inertia_y * self.hf**2 + self.fcrb = IS800_2007.cl_8_2_2_Unsupported_beam_bending_fcrb( + self.material_property.modulus_of_elasticity, + self.effective_length / self.section_property.rad_of_gy_y, + self.hf / self.section_property.flange_thickness + ) + + if self.section_class_girder == KEY_Plastic or self.section_class_girder == KEY_Compact: + self.beta_b_lt = 1.0 + else: + self.beta_b_lt = ( + self.section_property.elast_sec_mod_z + / self.section_property.plast_sec_mod_z + ) + if self.section_property.type == "Rolled": + alpha_lt = 0.21 + else: + alpha_lt = 0.49 + lambda_lt = IS800_2007.cl_8_2_2_1_elastic_buckling_moment_fcrb( + self.material_property.fy, self.fcrb + ) + phi_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_phi_lt( + alpha_lt, lambda_lt + ) + X_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_stress_reduction_factor( + phi_lt, lambda_lt + ) + fbd = IS800_2007.cl_8_2_2_Unsupported_beam_bending_compressive_stress( + X_lt, self.material_property.fy, self.gamma_m0 + ) + bending_strength_section = IS800_2007.cl_8_2_2_Unsupported_beam_bending_strength( + self.section_property.plast_sec_mod_z, + self.section_property.elast_sec_mod_z, + fcd=fbd, + section_class=self.section_class_girder + ) + + # self.beta_b_lt = beta_b + self.alpha_lt = alpha_lt + # self.lambda_lt = lambda_lt + self.phi_lt = phi_lt + self.X_lt = X_lt + self.fbd_lt = fbd + self.lateral_tb = self.fcrb * 10 ** -6 + print('Inside bending_strength 2.1', fbd, self.section_property.plast_sec_mod_z) + if self.high_shear_check: + if self.section_class_girder == KEY_Plastic or self.section_class_girder == KEY_Compact: + bending_strength_section = self.bending_strength_reduction(self, Md=bending_strength_section + ) + else: + bending_strength_section = ( + self.beta_b_lt + * self.section_property.plast_sec_mod_z + * fbd + ) + print('Inside bending_strength 2', self.It, self.hf, self.Iw, self.fcrb, self.beta_b_lt, alpha_lt, + lambda_lt, phi_lt, X_lt, fbd, bending_strength_section) + self.bending_strength_section_reduced = bending_strength_section + return bending_strength_section + + def bending_strength_reduction(self, Md, axis): + if axis == 'y': + Zp = self.section_property.plast_sec_mod_y + force = self.load.shear_force_yy + Vd = self.V_d_yy + else: + Zp = self.section_property.plast_sec_mod_z + force = self.load.shear_force_zz + Vd = self.V_d_zz + + Zfd = (Zp - + (self.section_property.depth ** 2 * self.section_property.web_thickness / 4) + ) + Mfd = Zfd * self.material_property.fy / self.gamma_m0 + beta = ((2 * force / (Vd * 10 ** 3)) - 1) ** 2 + Mdv = (Md - beta * (Md - Mfd)) + print('Inside bending_strength_reduction', Mdv, Md, beta, Mfd, Zfd) + self.bending_strength_section_reduced_by = Mfd + self.beta_reduced = beta + if ( + Mdv + <= 1.2 + * self.section_property.plast_sec_mod_z + * self.material_property.fy + / self.gamma_m0 + ): + return Mdv + else: + return ( + 1.2 + * self.section_property.plast_sec_mod_z + * self.material_property.fy + / self.gamma_m0 + ) + + def Channels_Classification(self, depth, thickness_web, f_y): + epsilon = math.sqrt(250 / int(f_y)) + d_t = depth / thickness_web + + if d_t <= (42 * epsilon): + section_class = KEY_Plastic + elif d_t <= (42 * epsilon): + section_class = KEY_Compact + elif d_t <= (42 * epsilon): + section_class = KEY_SemiCompact + else: + section_class = 'Slender' + + return section_class + + def design_bending_strength_purlins(self, section_class, Zp, Ze, fy, gamma_mo, high_shear_check, axis): + beta_b = 1.0 if section_class == KEY_Plastic or KEY_Compact else Ze / Zp + Md = beta_b * Zp * fy / gamma_mo + if Md < 1.2 * Ze * fy / gamma_mo: + M_d = Md + else: + M_d = 1.2 * Ze * fy / gamma_mo + + bending_strength_section = self.bending_strength_reduction(self, M_d, axis) + if high_shear_check: + if self.section_class == KEY_Plastic or self.section_class == KEY_Compact: + bending_strength_section = bending_strength_section + else: + bending_strength_section = Ze * fy / gamma_mo + else: + bending_strength_section = M_d + + return bending_strength_section + + def beam_M_cr_fcrb(self, E, meu, Iy, It, Iw, Llt, beta_b, Zp, hf, ry, tf): + G = E / (2 + 2 * meu) + fcrb = (1.1 * math.pi ** 2 * E / (Llt / ry) ** 2) * math.sqrt(1 + (((Llt / ry) / (hf / tf)) ** 2) / 20) + M_cr_candidate1 = math.sqrt((math.pi ** 2 * E * Iy / Llt ** 2) * (G * It + (math.pi ** 2 * E * Iw / Llt ** 2))) + M_cr_candidate2 = beta_b * Zp * fcrb + return [min(M_cr_candidate1, M_cr_candidate2), fcrb] + + def non_slenderness_ratio_purlin(self, betab, Zp, Ze, fy, Mcr, fcrb=0): + if (betab * Zp * fy / Mcr) ** 0.5 <= (1.2 * Ze * fy / Mcr) ** 0.5: + if (betab * Zp * fy / Mcr) ** 0.5 == math.sqrt(fy / fcrb): + return math.sqrt(fy / fcrb) + else: + return math.sqrt(fy / fcrb) + else: + return math.sqrt(fy / fcrb) + + def X_lt_calc(self, phi_lt, lambda_lt): + si = 1 / (phi_lt + (phi_lt ** 2 - lambda_lt ** 2) ** 0.5) + if si <= 1.0: + return si + else: + return -1 + + def web_resistance_check(self, m_inertia, Ze, Zp, rg, axis): + [M_cr, fcrb] = self.beam_M_cr_fcrb( + self, + self.material_property.modulus_of_elasticity, + 0.3, + m_inertia, + self.It, + self.Iw, + self.effective_length * 1e3, self.beta_b_lt, Zp, self.hf, + rg, self.section_property.flange_thickness + ) + + if self.section_property.type == "Rolled": + alpha_lt = 0.21 + else: + alpha_lt = 0.49 + lambda_lt = self.non_slenderness_ratio_purlin( + self, + self.beta_b_lt, + Zp, Ze, + self.material_property.fy, + M_cr, + fcrb + ) + phi_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_phi_lt( + alpha_lt, lambda_lt + ) + X_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_stress_reduction_factor( + phi_lt, lambda_lt + ) + fbd = IS800_2007.cl_8_2_2_Unsupported_beam_bending_compressive_stress( + X_lt, self.material_property.fy, self.gamma_m0 + ) + bending_strength_section = IS800_2007.cl_8_2_2_Unsupported_beam_bending_strength( + Zp, + Ze, + fcd=fbd, + section_class=self.section_class, + ) + if axis == 'y': + self.M_cr_y = M_cr + self.fcrb_y = fcrb + self.lambda_lt_y = lambda_lt + self.phi_lt_y = phi_lt + self.X_lt_y = X_lt + self.fbd_y = fbd + self.imperfection_factor = alpha_lt + elif axis == 'z': + self.M_cr_z = M_cr + self.fcrb_z = fcrb + self.lambda_lt_z = lambda_lt + self.phi_lt_z = phi_lt + self.X_lt_z = X_lt + self.fbd_z = fbd + self.imperfection_factor = alpha_lt + + return bending_strength_section + + def buckling_resistance_check(self, M_y, M_z, M_d_y, M_d_z): + if (M_y / M_d_y) + M_z / M_d_z <= 1.0: + return True + else: + return False + + def serviceability_check(self, w, Ze, mi): + deflection = (5 * w * self.length ** 4) / (384 * Ze * mi) + return deflection + + def section_classification(self, design_dictionary, trial_section=""): + """Classify the sections based on Table 2 of IS 800:2007""" + print(f"Inside section_classification") + local_flag = True + self.input_modified = [] + self.input_section_list = [] + self.input_section_classification = {} + lambda_check = False + for trial_section in self.sec_list: + trial_section = trial_section.strip("'") + self.section_property = self.section_connect_database(self, trial_section) + print(f"Type of section{self.section_property.designation}") + if self.section_property.type == "Rolled": + self.effective_depth = (self.section_property.depth - 2 * ( + self.section_property.flange_thickness + self.section_property.root_radius)) + + web_ratio = self.effective_depth / self.section_property.web_thickness + + web_class = self.Channels_Classification( + self, + self.section_property.depth - 2 * ( + self.section_property.flange_thickness + self.section_property.root_radius), + self.section_property.web_thickness, + self.material_property.fy, + ) + + flange_class = IS800_2007.Table2_i( + self.section_property.flange_width / 2, + self.section_property.flange_thickness, + self.material_property.fy, self.section_property.type + )[0] + ''' + web_class = IS800_2007.Table2_iii( + self.section_property.depth - 2 * ( + self.section_property.flange_thickness + self.section_property.root_radius), + self.section_property.web_thickness, + self.material_property.fy, + ) + ''' + flange_ratio = self.section_property.flange_width / 2 / self.section_property.flange_thickness + else: + flange_class = IS800_2007.Table2_i( + ( + (self.section_property.flange_width / 2) + # - (self.section_property.web_thickness / 2) + ), + self.section_property.flange_thickness, + self.section_property.fy, + self.section_property.type, + )[0] + + web_class = self.Channels_Classification( + self, + ( + self.section_property.depth - 2 * ( + self.section_property.flange_thickness) + ), + self.section_property.web_thickness, + self.material_property.fy, # classification_type="Axial compression", + ) + self.effective_depth = (self.section_property.depth - 2 * self.section_property.flange_thickness) + + web_ratio = ( + self.section_property.depth - 2 * self.section_property.flange_thickness) / self.section_property.web_thickness + + flange_ratio = self.section_property.flange_width / 2 / self.section_property.flange_thickness + print(f"\n \n \n flange_class {flange_class} \n web_class{web_class} \n \n") + if flange_class == "Slender" or web_class == "Slender": + self.section_class = "Slender" + else: + if flange_class == KEY_Plastic and web_class == KEY_Plastic: + self.section_class = KEY_Plastic + elif flange_class == KEY_Plastic and web_class == KEY_Compact: + self.section_class = KEY_Compact + elif flange_class == KEY_Plastic and web_class == KEY_SemiCompact: + self.section_class = KEY_SemiCompact + elif flange_class == KEY_Compact and web_class == KEY_Plastic: + self.section_class = KEY_Compact + elif flange_class == KEY_Compact and web_class == KEY_Compact: + self.section_class = KEY_Compact + elif flange_class == KEY_Compact and web_class == KEY_SemiCompact: + self.section_class = KEY_SemiCompact + elif flange_class == KEY_SemiCompact and web_class == KEY_Plastic: + self.section_class = KEY_SemiCompact + elif flange_class == KEY_SemiCompact and web_class == KEY_Compact: + self.section_class = KEY_SemiCompact + elif flange_class == KEY_SemiCompact and web_class == KEY_SemiCompact: + self.section_class = KEY_SemiCompact + + print(f"section class is {self.section_class}") + self.Zp_req = self.load.moment * self.gamma_m0 / self.material_property.fy + + self.effective_length = self.length + + if self.section_property.plast_sec_mod_z >= self.Zp_req: + self.It = self.section_property.It + self.hf = self.section_property.depth - self.section_property.flange_thickness + self.Iw = self.section_property.Iw + + self.input_section_list.append(trial_section) + self.input_section_classification.update( + {trial_section: [self.section_class, flange_class, + web_class, flange_ratio, + web_ratio, self.It, self.hf, + self.Iw]}) + + if len(self.input_section_list) == 0: + local_flag = False + logger.warning('No section passed found') + else: + local_flag = True + return local_flag + + def effective_length_beam(self, design_dictionary, length): + print(f"Inside effective_length_beam") + self.Loading = design_dictionary[KEY_LOAD] # 'Normal'or 'Destabilizing' + # self.Latex_length = design_dictionary[KEY_LENGTH_OVERWRITE] + if design_dictionary[KEY_LENGTH_OVERWRITE] == 'NA': + if self.support == KEY_DISP_SUPPORT1: + self.Torsional_res = design_dictionary[KEY_TORSIONAL_RES] + self.Warping = design_dictionary[KEY_WARPING_RES] + self.effective_length = IS800_2007.cl_8_3_1_EffLen_Simply_Supported( + Torsional=self.Torsional_res, + Warping=self.Warping, + length=length, + depth=self.section_property.depth, + load=self.Loading, + ) + print(f"Working 1 {self.effective_length}") + elif self.support == KEY_DISP_SUPPORT2: + self.Support = design_dictionary[KEY_SUPPORT_TYPE] + self.Top = design_dictionary[KEY_SUPPORT_TYPE2] + self.effective_length = IS800_2007.cl_8_3_3_EffLen_Cantilever( + Support=self.Support, + Top=self.Top, + length=length, + load=self.Loading, + ) + print(f"Working 2 {self.effective_length}") + else: + if self.support == KEY_DISP_SUPPORT1: + self.Torsional_res = design_dictionary[KEY_TORSIONAL_RES] + self.Warping = design_dictionary[KEY_WARPING_RES] + + elif self.support == KEY_DISP_SUPPORT2: + self.Support = design_dictionary[KEY_SUPPORT_TYPE] + self.Top = design_dictionary[KEY_SUPPORT_TYPE2] + + try: + if float(design_dictionary[KEY_LENGTH_OVERWRITE]) <= 0: + design_dictionary[KEY_LENGTH_OVERWRITE] = 'NA' + else: + length = length * float(design_dictionary[KEY_LENGTH_OVERWRITE]) + + self.effective_length = length + print(f"Working 3 {self.effective_length}") + except: + print(f"Inside effective_length_beam", type(design_dictionary[KEY_LENGTH_OVERWRITE])) + logger.warning("Invalid Effective Length Parameter.") + logger.info('Effective Length Parameter is set to default: 1.0') + design_dictionary[KEY_LENGTH_OVERWRITE] = '1.0' + self.effective_length_beam(self, design_dictionary, length) + print(f"Working 4 {self.effective_length}") + print(f"Inside effective_length_beam", self.effective_length, design_dictionary[KEY_LENGTH_OVERWRITE]) + + def lambda_lt_check_member_type(self, Mcr=0, fcrb=0, Zp=0, f_y=0, Ze=0, beta_b=0): + lambda_lt_1 = math.sqrt(beta_b * Zp * f_y / Mcr) + lambda_lt_2 = math.sqrt(f_y / fcrb) + lambda_lt_check = math.sqrt(1.2 * Ze * f_y / Mcr) + if lambda_lt_1 == lambda_lt_2: + if lambda_lt_1 <= lambda_lt_check: + return lambda_lt_1 + logger.warning(" Issues with the non-dimensional slenderness ratio Lambda_lt") + + def common_checks_1(self, section, step=1, list_result=[], list_1=[]): + if step == 1: + print(f"Working correct here") + elif step == 2: + # reduction of the area based on the connection requirements (input from design preferences) + if self.effective_area_factor < 1.0: + self.effective_area = round( + self.effective_area * self.effective_area_factor, 2 + ) + + + elif step == 3: + # 2.1 - Buckling curve classification and Imperfection factor + if self.section_property.type == 'Rolled': + self.buckling_class = 'c' + self.imperfection_factor = IS800_2007.cl_7_1_2_1_imperfection_factor( + buckling_class=self.buckling_class + ) + elif step == 4: + # self.slenderness = self.effective_length / min(self.section_property.rad_of_gy_z, self.section_property.rad_of_gy_y) * 1000 + print( + f"\n data sent " + f" self.material_property.fy {self.material_property.fy}" + f"self.gamma_m0 {self.gamma_m0}" + f"self.slenderness {self.slenderness}" + f" self.imperfection_factor {self.imperfection_factor}" + f"self.section_property.modulus_of_elasticity {self.section_property.modulus_of_elasticity}" + ) + + list_cl_7_1_2_1_design_compressisive_stress = ( + IS800_2007.cl_7_1_2_1_design_compressisive_stress( + self.material_property.fy, + self.gamma_m0, + self.slenderness, + self.imperfection_factor, + self.section_property.modulus_of_elasticity, + check_type=list_result, + ) + ) + for x in list_cl_7_1_2_1_design_compressisive_stress: + print(f"x {x} ") + self.euler_buckling_stress = list_cl_7_1_2_1_design_compressisive_stress[0] + self.nondimensional_effective_slenderness_ratio = ( + list_cl_7_1_2_1_design_compressisive_stress[1] + ) + self.phi = list_cl_7_1_2_1_design_compressisive_stress[2] + self.stress_reduction_factor = list_cl_7_1_2_1_design_compressisive_stress[ + 3 + ] + self.design_compressive_stress_fr = ( + list_cl_7_1_2_1_design_compressisive_stress[4] + ) + self.design_compressive_stress = ( + list_cl_7_1_2_1_design_compressisive_stress[5] + ) + self.design_compressive_stress_max = ( + list_cl_7_1_2_1_design_compressisive_stress[6] + ) + elif step == 5: + # 1- Based on optimum UR + if not "UR" in list_1: + self.ur = 0 + self.cost = ( + ( + self.section_property.unit_mass + * self.section_property.area + * 1e-4 + ) + * self.length + * self.steel_cost_per_kg + ) + list_1.extend(["UR", "Cost"]) + list_result.extend([self.ur, self.cost]) + + self.optimum_section_ur_results[self.ur] = {} + list_2 = list_result.copy() + for j in list_1: + # k = 0 + for k in list_2: + self.optimum_section_ur_results[self.ur][j] = k + # k += 1 + list_2.pop(0) + break + + # 2- Based on optimum cost + self.optimum_section_cost_results[self.cost] = {} + + list_2 = list_result.copy() # Why? + for j in list_1: + for k in list_2: + self.optimum_section_cost_results[self.cost][j] = k + list_2.pop(0) + break + print( + f"\n self.optimum_section_cost_results {self.optimum_section_cost_results}" + f"\n self.optimum_section_ur_results {self.optimum_section_ur_results}" + ) + elif step == 6: + self.single_result[self.sec_profile] = {} + list_2 = list_result.copy() + for j in list_1: + # k = 0 + for k in list_2: + self.single_result[self.sec_profile][j] = k + # k += 1 + list_2.pop(0) + break + print(f"\n self.single_result {self.single_result}") + + def list_changer(self, change, list, list_name, check=True): + + list.extend( + [self.bending_strength_section_reduced_by, self.beta_reduced, self.M_d_zz, self.M_d_yy]) + list_name.extend([ + "Mfd", + "Beta_reduced", + "M_d_zz", + "M_d_yy" + ]) + # Latex para also + list.extend( + [self.web_buckling_check, self.effective_depth, self.web_buckling_check1, + self.section_class, self.effective_area, self.V_d_yy, self.V_d_zz, self.high_shear_check_yy, + self.high_shear_check_zz, self.M_d_yy1, self.M_d_zz1, self.effective_length, + self.ur, self.cost, self.beta_b_lt, self.buckling_class]) + list_name.extend([ + 'Web.Buckling', + 'Reduced.depth', + 'Buckling.resistance', + "Section class", + "Effective area", + "Shear Strength YY", + "Shear Strength ZZ", + "High Shear check YY", + "High Shear check ZZ", + "Bending Strength YY", + "Bending Strength ZZ", + "Effective_length", + "UR", + "Cost", + "Beta_b", + "Buckling.class" + ]) + # Web buckling parameters + # if self.web_buckling_check and (self.support_cndition_shear_buckling == KEY_DISP_SB_Option[0] or self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1] ) : + # list.extend( + # [self.K_v, self.tau_crc, self.lambda_w, self.tau_b, + # self.V_cr]) + # list_name.extend([ + # 'Kv', + # 'tau_crc', + # 'lambda_w', + # 'tau_b', + # "V_cr" + # ]) + + # if self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1] and self.web_buckling_check: + # list.extend( + # [self.Mfr, self.load.moment / ( + # self.section_property.depth - self.section_property.flange_thickness) + # , self.c, self.phi_girder, self.s_girder, self.wtf_girder, self.sai_girder, self.fv_girder, + # self.V_p, self.V_tf_girder]) + # list_name.extend([ + # 'Mfr',#1 + # 'Nf', + # 'c', + # 'phi_girder', + # "s_girder", + # 'wtf_girder', + # 'sai_girder', + # 'fv_girder', + # 'V_p', + # 'V_tf_girder' + # ]) + # if change == 'Web Buckling': + # list.extend([self.I_eff_web, self.A_eff_web, self.r, self.buckling_class, + # self.imperfection_factor, + # self.slenderness, + # self.euler_buckling_stress, + # self.nondimensional_effective_slenderness_ratio, + # self.phi, + # self.stress_reduction_factor, + # self.design_compressive_stress_fr, + # self.design_compressive_stress_max, + # self.design_compressive_stress, + # self.section_capacity, + # self.F_wb]) + # + # list_name.extend([ + # "WebBuckling.I_eff",#1 + # "WebBuckling.A_eff",#1 + # "WebBuckling.r_eff",#1 + # "Buckling_class",#0 + # "IF",#0 + # "Effective_SR", + # "EBS", + # "ND_ESR", + # "phi", + # "SRF", + # "FCD_formula", + # "FCD_max", + # "FCD", + # "Capacity", + # "Web_crippling" + # ]) + + list.extend([self.It, + self.Iw, + self.imperfection_factor, + self.lambda_lt_y, + self.lambda_lt_z, + self.phi_lt_y, + self.phi_lt_z, + self.X_lt_y, + self.X_lt_z, + self.fbd_y, + self.fbd_z, + self.M_cr_y, + self.M_cr_z, + self.fcrb_y, + self.fcrb_z]) + + list_name.extend([ + "It", + "Iw", + "IF_lt", + "lambda_lt_yy", + "lambda_lt_zz", + "phi_lt_yy", + "phi_lt_zz", + "X_lt_yy", + "X_lt_zz", + "Fbd_yy", + "Fbd_zz", + "Mcr_yy", + "Mcr_zz", + "Fcrb_yy", + "Fcrb_zz" + ]) + print(list, list_name) + return list, list_name + + # def plate_girder_design(self, section): + # if self.support_cndition_shear_buckling == KEY_DISP_SB_Option[0]: + # self.tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(self.K_v, + # self.material_property.modulus_of_elasticity, + # 0.3,self.effective_depth, + # self.section_property.web_thickness) + # self.lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.fyw,self.tau_crc) + # self.tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(self.lambda_w, self.fyw) + # self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(self.tau_b, self.effective_depth * self.section_property.web_thickness) + # d_red = self.section_property.depth - 2*(self.section_property.flange_thickness + self.section_property.root_radius) + # tau_b = self.load.shear_force / (self.effective_depth * self.section_property.web_thickness) + # if tau_b <= self.fyw / math.sqrt(3): + # lambda_w = 0.8 + # else: + # lambda_w = min((tau_b*(math.sqrt(3)/self.fyw) - 1.64) / (-0.8), math.sqrt(tau_b*(math.sqrt(3)/self.fyw))) + # tau_crc = self.fyw / (math.sqrt(3) * lambda_w ** 2) + + def plate_girder_strength(self): + self.tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(self.K_v, + self.material_property.modulus_of_elasticity, + 0.3, self.effective_depth, + self.section_property.web_thickness) + self.lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.fyw, self.tau_crc) + self.tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(self.lambda_w, self.fyw) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(self.tau_b, + self.effective_depth * self.section_property.web_thickness) / 10 ** 3 + print('\n plate_girder_strength', '\n tau_crc', self.tau_crc, '\n self.lambda_w', self.lambda_w, + '\n self.tau_b', self.tau_b, '\n self.V_cr', self.V_cr) + + def plate_girder_strength2(self): + + self.plate_girder_strength(self) + self.phi_girder, self.M_fr_girder, self.s_girder, self.wtf_girder, self.sai_girder, self.fv_girder, self.V_tf_girder = IS800_2007.cl_8_4_2_2_TensionField( + self.c, + self.effective_depth, self.section_property.web_thickness, + self.fyw, self.section_property.flange_width, + self.section_property.flange_thickness, self.fyf, + self.load.moment / (self.section_property.depth - self.section_property.flange_thickness), + self.gamma_m0, self.effective_depth * self.section_property.web_thickness, self.tau_b, self.V_p) + + def results(self, design_dictionary): + _ = [i for i in self.optimum_section_ur if i < 1.0] + if len(_) == 1: + temp = _[0] + elif len(_) == 0: + temp = None + else: + temp = sorted(_)[0] + self.failed_design_dict = self.optimum_section_ur_results[temp] if temp is not None else None + print('self.failed_design_dict ', self.failed_design_dict) + + # sorting results from the dataset + # if len(self.input_section_list) > 1: + # results based on UR + if self.optimization_parameter == "Utilization Ratio": + filter_UR = filter( + lambda x: x <= min(self.allowable_utilization_ratio, 1.0), + self.optimum_section_ur + ) + self.optimum_section_ur = list(filter_UR) + + self.optimum_section_ur.sort() + print( + f"self.optimum_section_ur{self.optimum_section_ur} \n self.optimum_section_ur_results{self.optimum_section_ur_results}") + # print(f"self.result_UR{self.result_UR}") + + # selecting the section with most optimum UR + if len(self.optimum_section_ur) == 0: # no design was successful + logger.warning( + "The sections selected by the solver from the defined list of sections did not satisfy the Utilization Ratio (UR) " + "criteria" + ) + logger.error( + "The solver did not find any adequate section from the defined list." + ) + + self.design_status = False + + if self.failed_design_dict is None: + + logger.info( + "The details for the best section provided is being shown" + ) + self.failed_design_dict = self.optimum_section_ur_results + ur_vals = self.optimum_section_ur_results.keys() + self.result_UR = min(ur_vals) + self.design_status = True + + self.common_result( + self, + list_result=self.optimum_section_ur_results, + result_type=self.result_UR, + flag=True + ) + + elif len(self.failed_design_dict) > 0: + logger.info( + "The details for the best section provided is being shown" + ) + self.result_UR = self.failed_design_dict['UR'] # temp TODO @Rutvik + self.common_result( + self, + list_result=self.failed_design_dict, + result_type=None, + ) + logger.warning( + "Re-define the list of sections or check the Design Preferences option and re-design." + ) + else: + logger.warning( + "Plastic section modulus of selected sections is less than required." + ) + return + # self.design_status_list.append(self.design_status) + + else: + self.failed_design_dict = None + self.result_UR = self.optimum_section_ur[ + -1 + ] # optimum section which passes the UR check + print(f"self.result_UR{self.result_UR}") + self.design_status = True + self.common_result( + self, + list_result=self.optimum_section_ur_results, + result_type=self.result_UR, + ) + + else: # results based on cost + self.optimum_section_cost.sort() + + # selecting the section with most optimum cost + self.result_cost = self.optimum_section_cost[0] + self.design_status = True + # print results + # if len(self.optimum_section_ur) == 0: + # logger.warning( + # "The sections selected by the solver from the defined list of sections did not satisfy the Utilization Ratio (UR) " + # "criteria" + # ) + # logger.error( + # "The solver did not find any adequate section from the defined list." + # ) + # logger.info( + # "Re-define the list of sections or check the Design Preferences option and re-design." + # ) + # self.design_status = False + # self.design_status_list.append(self.design_status) + # pass + # else: + # if self.optimization_parameter == "Utilization Ratio": + # self.common_result( + # self, + # list_result=self.optimum_section_ur_results, + # result_type=self.result_UR, + # ) + # else: + # self.result_UR = self.optimum_section_cost_results[ + # self.result_cost + # ]["UR"] + # + # # checking if the selected section based on cost satisfies the UR + # if self.result_UR > min(self.allowable_utilization_ratio, 1.0): + # trial_cost = [] + # for cost in self.optimum_section_cost: + # self.result_UR = self.optimum_section_cost_results[ + # cost + # ]["UR"] + # if self.result_UR <= min( + # self.allowable_utilization_ratio, 1.0 + # ): + # trial_cost.append(cost) + # + # trial_cost.sort() + # + # if len(trial_cost) == 0: # no design was successful + # logger.warning( + # "The sections selected by the solver from the defined list of sections did not satisfy the Utilization Ratio (UR) " + # "criteria" + # ) + # logger.error( + # "The solver did not find any adequate section from the defined list." + # ) + # logger.info( + # "Re-define the list of sections or check the Design Preferences option and re-design." + # ) + # self.design_status = False + # self.design_status_list.append(self.design_status) + # print(f"design_status_list{self.design_status} \n") + # else: + # self.result_cost = trial_cost[ + # 0 + # ] # optimum section based on cost which passes the UR check + # self.design_status = True + # + # # results + # self.common_result( + # self, + # list_result=self.optimum_section_cost_results, + # result_type=self.result_cost, + # ) + # + # print(f"design_status_list2{self.design_status}") + self.design_status_list.append(self.design_status) + for status in self.design_status_list: + print('status list', status) + if status is False: + self.design_status = False + break + else: + self.design_status = True + + def common_result(self, list_result, result_type, flag=False): + if flag: + self.result_designation = list_result[result_type]["Designation"] + self.result_web_buckling_check = list_result[result_type]["Web.Buckling"] + self.result_section_class = list_result[result_type]["Section class"] + self.result_tc = round(list_result[result_type]["It"], 2) + self.result_wc = round(list_result[result_type]["Iw"], 2) + self.result_eff_d = 'NA' + self.result_buckling_resistance = 'NA' + self.result_effective_area = 'NA' + self.result_shear_yy = 'NA' + self.result_shear_zz = 'NA' + self.result_high_shear_yy = 'NA' + self.result_high_shear_zz = 'NA' + self.result_bending_yy = 'NA' + self.result_bending_zz = 'NA' + self.result_eff_len = 'NA' + self.result_cost = list_result[result_type]["Cost"] + self.result_betab = list_result[result_type]["Beta_b"] + self.result_mcr_yy = 'NA' + self.result_mcr_zz = 'NA' + self.result_IF_lt = 'NA' + self.result_tc = 'NA' + self.result_wc = 'NA' + self.result_phi_lt_zz = 'NA' + self.result_phi_lt_yy = 'NA' + self.result_lambda_lt_yy = 'NA' + self.result_lambda_lt_zz = 'NA' + self.result_X_lt_yy = 'NA' + self.result_X_lt_zz = 'NA' + self.result_Fbd_yy = 'NA' + self.result_Fbd_zz = 'NA' + self.result_Fcrb_yy = 'NA' + self.result_Fcrb_zz = 'NA' + self.result_resistance_bending_yy = 'NA' + self.result_resistance_bending_zz = 'NA' + self.result_buckling_class = 'NA' + return + + try: + self.result_designation = list_result[result_type]['Designation'] # TODO debug + logger.info( + "The section is {}. The {} section has {} flange({}) and {} web({}). [Reference: Cl 3.7, IS 800:2007].".format( + self.input_section_classification[self.result_designation][0], + self.result_designation, + self.input_section_classification[self.result_designation][1], + round(self.input_section_classification[self.result_designation][3], 2), + self.input_section_classification[self.result_designation][2], + round(self.input_section_classification[self.result_designation][4], 2) + ) + ) + # self.result_latex_tension_zone = list_result[result_type]["latex.tension_zone"] + self.result_web_buckling_check = list_result[result_type]["Web.Buckling"] + print('self.result_web_buckling_check', self.result_web_buckling_check) + self.result_eff_d = list_result[result_type]["Reduced.depth"] + + self.result_buckling_resistance = list_result[result_type]["Buckling.resistance"] + + self.result_section_class = list_result[result_type]["Section class"] + self.result_effective_area = round(list_result[result_type]["Effective area"], 2) + if self.effective_area_factor < 1.0: + logger.info( + "The actual effective area is {} mm2 and the reduced effective area is {} mm2 [Reference: Cl. 7.3.2, IS 800:2007]".format( + round((self.result_effective_area / self.effective_area_factor), 2), + self.result_effective_area, + ) + ) + + self.result_shear_yy = round(list_result[result_type]["Shear Strength YY"], 2) + self.result_shear_zz = round(list_result[result_type]["Shear Strength ZZ"], 2) + self.result_high_shear_yy = list_result[result_type]["High Shear check YY"] + self.result_high_shear_zz = list_result[result_type]["High Shear check ZZ"] + self.result_bending_yy = round(list_result[result_type]["M_d_yy"], 2) + self.result_bending_zz = round(list_result[result_type]["M_d_zz"], 2) + self.result_eff_len = round(list_result[result_type]["Effective_length"], 2) + self.result_cost = list_result[result_type]["Cost"] + self.result_betab = list_result[result_type]["Beta_b"] + self.result_buckling_class = list_result[result_type]["Buckling.class"] + + if self.result_web_buckling_check: + logger.warning( + "Thin web so take flange to resist moment and web to resist shear[Reference: Cl 8.2.1.1, IS 800:2007]") + + self.result_mcr_yy = round(list_result[result_type]['Mcr_yy'], 2) + self.result_mcr_zz = round(list_result[result_type]['Mcr_zz'], 2) + self.result_IF_lt = round(list_result[result_type]["IF_lt"], 2) + self.result_tc = round(list_result[result_type]["It"], 2) + self.result_wc = round(list_result[result_type]["Iw"], 2) + self.result_phi_lt_zz = round(list_result[result_type]["phi_lt_zz"], 2) + self.result_phi_lt_yy = round(list_result[result_type]["phi_lt_yy"], 2) + self.result_lambda_lt_yy = round(list_result[result_type]["lambda_lt_yy"], 2) + self.result_lambda_lt_zz = round(list_result[result_type]["lambda_lt_zz"], 2) + self.result_X_lt_yy = round(list_result[result_type]["X_lt_yy"], 2) + self.result_X_lt_zz = round(list_result[result_type]["X_lt_zz"], 2) + self.result_Fbd_yy = round(list_result[result_type]["Fbd_yy"], 2) + self.result_Fbd_zz = round(list_result[result_type]["Fbd_zz"], 2) + self.result_Fcrb_yy = round(list_result[result_type]["Fcrb_yy"], 2) + self.result_Fcrb_zz = round(list_result[result_type]["Fcrb_zz"], 2) + self.result_resistance_bending_yy = round(list_result[result_type]["Bending Strength YY"], 2) + self.result_resistance_bending_zz = round(list_result[result_type]["Bending Strength ZZ"], 2) + + # if self.web_buckling: + # + # self.result_bcI_eff = list_result[result_type]['WebBuckling.I_eff'] + # self.result_bcA_eff = list_result[result_type]['WebBuckling.A_eff'] + # self.result_bcr_eff = list_result[result_type]['WebBuckling.r_eff'] + # self.result_bc = list_result[result_type]['Buckling_class'] + # self.result_IF = round(list_result[result_type]["IF"], 2) + # self.result_eff_sr = round(list_result[result_type]["Effective_SR"], 2) + # self.result_ebs = round(list_result[result_type]["EBS"], 2) + # self.result_nd_esr = round(list_result[result_type]["ND_ESR"], 2) + # self.result_phi_zz = round(list_result[result_type]["phi"], 2) + # self.result_srf = round(list_result[result_type]["SRF"], 2) + # self.result_fcd_1_zz = round(list_result[result_type]["FCD_formula"], 2) + # self.result_fcd_2 = round(list_result[result_type]["FCD_max"], 2) + # self.result_fcd = round(list_result[result_type]["FCD"], 2) + # self.result_capacity = round(list_result[result_type]["Capacity"], 2) + # self.result_crippling = round(list_result[result_type]["Web_crippling"], 2) + # else: + # self.result_bc = 'NA' + # self.result_IF = 'NA' + # self.result_eff_sr = 'NA' + # self.result_lambda_vv = 'NA' + # self.result_lambda_psi = 'NA' + # self.result_ebs = 'NA' + # self.result_nd_esr = 'NA' + # self.result_phi_zz = 'NA' + # self.result_srf = 'NA' + # self.result_fcd_1_zz = 'NA' + # self.result_fcd_2 = 'NA' + # self.result_fcd = 'NA' + # self.result_capacity = 'NA' + # self.result_crippling = 'NA' + # if self.result_high_shear and self.input_section_classification[self.result_designation][ + # 0] != 'Semi-Compact': + # self.result_mfd = list_result[result_type]["Mfd"] + # self.result_beta_reduced = list_result[result_type]["Beta_reduced"] + # self.result_Md = list_result[result_type]["M_d"] + except: + self.result_designation = list_result["Designation"] + # logger.info( + # "The section is {}. The {} section has {} flange({}) and {} web({}). [Reference: Cl 3.7, IS 800:2007].".format( + # self.input_section_classification[self.result_designation][0], + # self.result_designation, + # self.input_section_classification[self.result_designation][1], + # round(self.input_section_classification[self.result_designation][3], 2), + # self.input_section_classification[self.result_designation][2], + # round(self.input_section_classification[self.result_designation][4], 2) + # ) + # ) + self.result_web_buckling_check = list_result["Web.Buckling"] + self.result_eff_d = list_result["Reduced.depth"] + self.result_buckling_crippling = list_result["Buckling.resistance"] + + self.result_section_class = list_result["Section class"] + self.result_effective_area = round(list_result["Effective area"], 2) + if self.effective_area_factor < 1.0: + logger.info( + "The actual effective area is {} mm2 and the reduced effective area is {} mm2 [Reference: Cl. 7.3.2, IS 800:2007]".format( + round((self.result_effective_area / self.effective_area_factor), 2), + self.result_effective_area, + ) + ) + + self.result_shear_yy = round(list_result["Shear Strength YY"], 2) + self.result_shear_zz = round(list_result["Shear Strength ZZ"], 2) + self.result_high_shear_yy = list_result["High Shear check YY"] + self.result_high_shear_zz = list_result["High Shear check ZZ"] + self.result_bending_yy = round(list_result["M_d_yy"], 2) + self.result_bending_zz = round(list_result["M_d_zz"], 2) + self.result_eff_len = round(list_result["Effective_length"], 2) + self.result_cost = list_result["Cost"] + self.result_betab = list_result["Beta_b"] + self.result_buckling_class = list_result["Buckling.class"] + + if self.result_web_buckling_check: + logger.warning( + "Thin web so take flange to resist moment and web to resist shear[Reference: Cl 8.2.1.1, IS 800:2007]") + + self.result_mcr_yy = round(list_result['Mcr_yy'], 2) + self.result_mcr_zz = round(list_result['Mcr_zz'], 2) + self.result_IF_lt = round(list_result["IF_lt"], 2) + self.result_tc = round(list_result["It"], 2) + self.result_wc = round(list_result["Iw"], 2) + self.result_phi_lt_zz = round(list_result["phi_lt_zz"], 2) + self.result_phi_lt_yy = round(list_result["phi_lt_yy"], 2) + self.result_lambda_lt_yy = round(list_result["lambda_lt_yy"], 2) + self.result_lambda_lt_zz = round(list_result["lambda_lt_zz"], 2) + self.result_X_lt_yy = round(list_result["X_lt_yy"], 2) + self.result_X_lt_zz = round(list_result["X_lt_zz"], 2) + self.result_Fbd_yy = round(list_result["Fbd_yy"], 2) + self.result_Fbd_zz = round(list_result["Fbd_zz"], 2) + self.result_Fcrb_yy = round(list_result["Fcrb_yy"], 2) + self.result_Fcrb_zz = round(list_result["Fcrb_zz"], 2) + self.result_resistance_bending_yy = round(list_result["Bending Strength YY"], 2) + self.result_resistance_bending_zz = round(list_result["Bending Strength ZZ"], 2) + + # if self.design_type == KEY_DISP_DESIGN_TYPE2_FLEXURE: + # self.result_mcr = round(list_result['Mcr'], 2) + # self.result_IF_lt = round(list_result["IF_lt"], 2) + # self.result_tc = round(list_result["It"], 2) + # self.result_wc = round(list_result["Iw"], 2) + # self.result_nd_esr_lt = round(list_result["ND_ESR_lt"], 2) + # self.result_phi_lt = round(list_result["phi_lt"], 2) + # self.result_srf_lt = round(list_result["SRF_lt"], 2) + # self.result_fcd__lt = round(list_result["FCD_lt"], 2) + # else: + # self.result_mcr = 'NA' + # self.result_IF_lt = 'NA' + # self.result_tc = 'NA' + # self.result_wc = 'NA' + # self.result_nd_esr_lt = 'NA' + # self.result_phi_lt = 'NA' + # self.result_srf_lt = 'NA' + # self.result_fcd__lt = 'NA' + # + # if self.web_buckling: + # + # self.result_bcI_eff = list_result['WebBuckling.I_eff'] + # self.result_bcA_eff = list_result['WebBuckling.A_eff'] + # self.result_bcr_eff = list_result['WebBuckling.r_eff'] + # self.result_bc = list_result['Buckling_class'] + # self.result_IF = round(list_result["IF"], 2) + # self.result_eff_sr = round(list_result["Effective_SR"], 2) + # self.result_ebs = round(list_result["EBS"], 2) + # self.result_nd_esr = round(list_result["ND_ESR"], 2) + # self.result_phi_zz = round(list_result["phi"], 2) + # self.result_srf = round(list_result["SRF"], 2) + # self.result_fcd_1_zz = round(list_result["FCD_formula"], 2) + # self.result_fcd_2 = round(list_result["FCD_max"], 2) + # self.result_fcd = round(list_result["FCD"], 2) + # self.result_capacity = round(list_result["Capacity"], 2) + # self.result_crippling = round(list_result["Web_crippling"], 2) + # else: + # self.result_bc = 'NA' + # self.result_IF = 'NA' + # self.result_eff_sr = 'NA' + # self.result_lambda_vv = 'NA' + # self.result_lambda_psi = 'NA' + # self.result_ebs = 'NA' + # self.result_nd_esr = 'NA' + # self.result_phi_zz = 'NA' + # self.result_srf = 'NA' + # self.result_fcd_1_zz = 'NA' + # self.result_fcd_2 = 'NA' + # self.result_fcd = 'NA' + # self.result_capacity = 'NA' + # self.result_crippling = 'NA' + # if self.result_high_shear and self.input_section_classification[self.result_designation][ + # 0] != 'Semi-Compact': + # self.result_mfd = list_result["Mfd"] + # self.result_beta_reduced = list_result["Beta_reduced"] + # self.result_Md = list_result["M_d"] + + ### start writing save_design from here! + def save_design(self, popup_summary): + # print('self.design_status', self.design_status,'len(self.failed_design_dict)', len(self.failed_design_dict)) + if (self.design_status and self.failed_design_dict is None) or ( + not self.design_status and len(self.failed_design_dict) > 0): # TODO @Rutvik + self.section_property = self.section_connect_database(self, self.result_designation) + if self.sec_profile == 'Columns' or self.sec_profile == 'Beams' or self.sec_profile == VALUES_SECTYPE[1]: + self.report_column = {KEY_DISP_SEC_PROFILE: "ISection", + KEY_DISP_SECSIZE: (self.section_property.designation, self.sec_profile), + KEY_DISP_COLSEC_REPORT: self.section_property.designation, + KEY_DISP_MATERIAL: self.section_property.material, + # KEY_DISP_APPLIED_AXIAL_FORCE: self.section_property., + KEY_REPORT_MASS: self.section_property.mass, + KEY_REPORT_AREA: round(self.section_property.area * 1e-2, 2), + KEY_REPORT_DEPTH: self.section_property.depth, + KEY_REPORT_WIDTH: self.section_property.flange_width, + KEY_REPORT_WEB_THK: self.section_property.web_thickness, + KEY_REPORT_FLANGE_THK: self.section_property.flange_thickness, + KEY_DISP_FLANGE_S_REPORT: self.section_property.flange_slope, + KEY_REPORT_R1: self.section_property.root_radius, + KEY_REPORT_R2: self.section_property.toe_radius, + KEY_REPORT_IZ: round(self.section_property.mom_inertia_z * 1e-4, 2), + KEY_REPORT_IY: round(self.section_property.mom_inertia_y * 1e-4, 2), + KEY_REPORT_RZ: round(self.section_property.rad_of_gy_z * 1e-1, 2), + KEY_REPORT_RY: round(self.section_property.rad_of_gy_y * 1e-1, 2), + KEY_REPORT_ZEZ: round(self.section_property.elast_sec_mod_z * 1e-3, 2), + KEY_REPORT_ZEY: round(self.section_property.elast_sec_mod_y * 1e-3, 2), + KEY_REPORT_ZPZ: round(self.section_property.plast_sec_mod_z * 1e-3, 2), + KEY_REPORT_ZPY: round(self.section_property.plast_sec_mod_y * 1e-3, 2)} + + self.report_input = \ + { # KEY_MAIN_MODULE: self.mainmodule, + KEY_MODULE: self.module, # "Axial load on column " + KEY_DISP_SHEAR + '*': self.load.shear_force * 10 ** -3, + KEY_DISP_BEAM_MOMENT_Latex + '*': self.load.moment * 10 ** -6, + KEY_DISP_LENGTH_BEAM: self.result_eff_len, + KEY_DISP_SEC_PROFILE: self.sec_profile, + KEY_DISP_SECSIZE: str(self.sec_list), + KEY_MATERIAL: self.material, + "Selected Section Details": self.report_column, + KEY_BEAM_SUPP_TYPE: self.latex_design_type, + } + + # if self.latex_design_type == VALUES_SUPP_TYPE_temp[0]: + # self.report_input.update({ + # KEY_DISP_BENDING: self.bending_type}) + # elif self.latex_design_type == VALUES_SUPP_TYPE_temp[1]: + # self.report_input.update({ + # KEY_BEAM_SUPP_TYPE_DESIGN: self.support, + # # KEY_DISP_BENDING: self.bending_type, + # }) + self.report_input.update({ + KEY_DISP_SUPPORT: self.support, + KEY_DISP_ULTIMATE_STRENGTH_REPORT: self.material_property.fu, + KEY_DISP_YIELD_STRENGTH_REPORT: self.material_property.fy, + "End Conditions - " + str(self.support): "TITLE", + }) + # if self.Latex_length == 'NA': + if self.support == KEY_DISP_SUPPORT1: + self.report_input.update({ + DISP_TORSIONAL_RES: self.Torsional_res, + DISP_WARPING_RES: self.Warping}) + else: + self.report_input.update({ + DISP_SUPPORT_RES: self.Support, + DISP_TOP_RES: self.Top}) + self.report_input.update({ + "Design Preference": "TITLE", + KEY_DISP_EFFECTIVE_AREA_PARA: self.effective_area_factor, + KEY_DISP_CLASS: self.allow_class, + KEY_DISP_LOAD: self.Loading, + KEY_DISPP_LENGTH_OVERWRITE: self.latex_efp, + KEY_DISP_BEARING_LENGTH + ' (mm)': self.bearing_length, + + }) + # if self.latex_design_type == VALUES_SUPP_TYPE_temp[0] and self.result_web_buckling_check: + # self.report_input.update({ + # KEY_ShearBuckling: self.support_cndition_shear_buckling + # }) + # self.report_input.update({ + # # KEY_DISP_SEC_PROFILE: self.sec_profile, + # "I Section - Mechanical Properties": "TITLE", + # }) + self.report_input.update() + self.report_check = [] + + t1 = ('Selected', 'Selected Member Data', '|p{5cm}|p{2cm}|p{2cm}|p{2cm}|p{4cm}|') + self.report_check.append(t1) + + t1 = ('SubSection', 'Effective Area', '|p{4cm}|p{1.5cm}|p{9.5cm}|p{1cm}|') + self.report_check.append(t1) + t1 = ('Effective Area ($mm^2$)', ' ', + sectional_area_change(round(self.result_effective_area, 2), round(self.section_property.area, 2), + self.effective_area_factor), + ' ') + self.report_check.append(t1) + + # t1 = ('SubSection', 'Section parameters', '|p{4cm}|p{1.5cm}|p{9.5cm}|p{1cm}|') + # self.report_check.append(t1) + # t1 = ('d_{web}', ' ', + # sectional_area_change(round(self.result_effective_area,2), round(self.section_property.area,2), + # self.effective_area_factor), + # ' ') + # self.report_check.append(t1) + + t1 = ('SubSection', 'Section Classification', '|p{3cm}|p{3.5cm}|p{8.5cm}|p{1cm}|') + self.report_check.append(t1) + t1 = ('Web Class', 'Neutral Axis at Mid-Depth', + cl_3_7_2_section_classification_web(round(self.result_eff_d, 2), + round(self.section_property.web_thickness, 2), round( + self.input_section_classification[self.result_designation][4], 2), + self.epsilon, self.section_property.type, + self.input_section_classification[self.result_designation][2]), + ' ') + self.report_check.append(t1) + t1 = ('Flange Class', self.section_property.type, + cl_3_7_2_section_classification_flange(round(self.section_property.flange_width / 2, 2), + round(self.section_property.flange_thickness, 2), round( + self.input_section_classification[self.result_designation][3], 2), + self.epsilon, + self.input_section_classification[self.result_designation][1]), + ' ') + self.report_check.append(t1) + t1 = ('Section Class', ' ', + cl_3_7_2_section_classification( + self.input_section_classification[self.result_designation][0]), + ' ') + self.report_check.append(t1) + + t1 = ('SubSection', 'Web Slenderness Check', '|p{3cm}|p{4cm}|p{6cm}|p{3 cm}|') + self.report_check.append(t1) + t1 = ( + KEY_DISP_Web_Buckling, + cl_8_2_1web_buckling_required(round(self.epsilon, 2), round(67 * self.epsilon, 2)), + cl_8_2_1web_buckling_1(self.result_eff_d, self.section_property.web_thickness, + round(self.result_eff_d / self.section_property.web_thickness, 2), + self.result_web_buckling_check), + get_pass_fail(67 * self.epsilon, round(self.result_eff_d / self.section_property.web_thickness, 2), + relation="Custom")) + self.report_check.append(t1) + if self.result_web_buckling_check: + t1 = ('SubSection', 'Shear Strength Results: ' + self.support_cndition_shear_buckling, + '|p{3.5cm}|p{1.5cm}|p{10cm}|p{1cm}|') + self.report_check.append(t1) + if self.support_cndition_shear_buckling == KEY_DISP_SB_Option[0]: + t1 = (KEY_DISP_K_v_latex, ' ', + cl_8_4_2_2_KV(self.result_web_buckling_simple_kv, self.support_cndition_shear_buckling), + + ' ') + elif self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1]: + t1 = (KEY_DISP_Transverse_Stiffener_spacing, ' ', + cl_8_4_2_2_Transverse_Stiffener_spacing(self.result_web_buckling_simple_c), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_K_v_latex, ' ', + cl_8_4_2_2_KV(self.result_web_buckling_simple_kv, self.support_cndition_shear_buckling, + self.result_web_buckling_simple_c, self.result_eff_d), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_Elastic_Critical_shear_stress_web, ' ', + cl_8_4_2_2_taucrc(self.result_web_buckling_simple_kv, 2 * 10 ** 5, 0.3, + self.result_eff_d, + self.section_property.web_thickness, + self.result_web_buckling_simple_tau_crc), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_slenderness_ratio_web, ' ', + cl_8_4_2_2_slenderness_ratio(self.fyw, self.result_web_buckling_simple_lambda_w, + self.result_web_buckling_simple_tau_crc), + ' ') + self.report_check.append(t1) + + t1 = (KEY_OUT_DISP_WELD_SHEAR_STRESS, ' ', + cl_8_4_2_2_shearstress_web(self.fyw, self.result_web_buckling_simple_lambda_w, + self.result_web_buckling_simple_tau_b), + ' ') + self.report_check.append(t1) + + if self.support_cndition_shear_buckling == KEY_DISP_SB_Option[0]: + t1 = (KEY_DISP_DESIGN_STRENGTH_SHEAR + '(V_{d})', self.load.shear_force * 10 ** -3, + cl_8_4_2_2_shearstrength(self.result_eff_d, self.section_property.web_thickness, + self.result_web_buckling_simple_V_cr, + self.result_web_buckling_simple_tau_b, self.result_shear), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_ALLOW_SHEAR, ' ', + cl_8_2_1_2_shear_check(round(self.result_shear, 2), round(0.6 * self.result_shear, 2), + self.result_high_shear, self.load.shear_force * 10 ** -3), + get_pass_fail(self.load.shear_force * 10 ** -3, round(0.6 * self.result_shear, 2), + relation="Warn", M1=self.result_high_shear)) + self.report_check.append(t1) + + elif self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1]: + t1 = (KEY_DISP_BUCKLING_STRENGTH + '(V_p)', ' ', + cl_8_4_1_plastic_shear_resistance_Vp(self.result_eff_d, self.section_property.web_thickness, + self.fyw, self.result_web_buckling_simple_V_p_girder + ), + ' ') + self.report_check.append(t1) + + t1 = ('N_f (N)', ' ', + cl_8_4_2_2_N_f(self.section_property.depth, + self.section_property.flange_thickness, + self.section_property.depth - self.section_property.flange_thickness, + round(self.load.moment / ( + self.section_property.depth - self.section_property.flange_thickness), + 2), self.load.moment + ), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_reduced_moment + '(M_{fr})', ' ', + cl_8_4_2_2_TensionField_reduced_moment(self.result_web_buckling_simple_Mfr, + self.section_property.flange_width, + self.section_property.flange_thickness, + self.fyf, round(self.load.moment / ( + self.section_property.depth - self.section_property.flange_thickness), 2) + ), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_tension_field_incline, ' ', + cl_8_4_2_2_TensionField_phi(self.result_web_buckling_simple_phi_girder, + self.result_web_buckling_simple_c, self.result_eff_d + ), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_AnchoragelengthTensionField, ' ', + cl_8_4_2_2_TensionField_anchorage_length(self.result_web_buckling_simple_s_girder, + self.result_web_buckling_simple_phi_girder, + self.result_web_buckling_simple_Mfr, self.fyw, + self.section_property.web_thickness + ), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_WidthTensionField, ' ', + cl_8_4_2_2_KEY_DISP_WidthTensionField(self.result_eff_d, + self.result_web_buckling_simple_phi_girder, + self.result_web_buckling_simple_c, + self.result_web_buckling_simple_s_girder, + self.result_web_buckling_simple_wtf_girder + ), + ' ') + self.report_check.append(t1) + # t1 = (KEY_DISP_reduced_moment + '(M_{fr}', ' ', + # cl_8_4_2_2_TensionField_reduced_moment(self.result_eff_d, + # self.result_web_buckling_simple_phi_girder, + # self.result_web_buckling_simple_c, + # self.result_web_buckling_simple_s_girder,self.result_web_buckling_simple_wtf_girder + # ), + # ' ') + # self.report_check.append(t1) + t1 = (KEY_DISP_Yield_Strength_Tension_field, ' ', + cl_8_4_2_2_Yield_Strength_Tension_field(self.fyw, + self.result_web_buckling_simple_tau_b, + self.result_web_buckling_simple_phi_girder, + self.result_web_buckling_simple_fv_girder + ), + ' ') + self.report_check.append(t1) + t1 = (KEY_DISP_DESIGN_STRENGTH_SHEAR + '(V_{d})', self.load.shear_force * 10 ** -3, + cl_8_4_2_2_shearstrength_tensionfield( + self.effective_depth * self.section_property.web_thickness, + self.result_web_buckling_simple_tau_b, self.result_web_buckling_simple_V_p_girder, + self.result_shear, self.section_property.web_thickness, + self.result_web_buckling_simple_wtf_girder, self.result_web_buckling_simple_fv_girder, + self.result_web_buckling_simple_phi_girder, + round(self.result_web_buckling_simple_fV_tf_girder * 10 ** -3, 2)), + ' ') + self.report_check.append(t1) + + + else: + + t1 = ('SubSection', 'Shear Strength Results', '|p{4cm}|p{5cm}|p{5.5cm}|p{1.5cm}|') + self.report_check.append(t1) + + t1 = (KEY_DISP_DESIGN_STRENGTH_SHEAR, self.load.shear_force * 10 ** -3, + cl_8_4_shear_yielding_capacity_member_(self.section_property.depth, + self.section_property.web_thickness, + self.material_property.fy, + self.gamma_m0, round(self.result_shear, 2)), + get_pass_fail(self.load.shear_force * 10 ** -3, round(self.result_shear, 2), relation="lesser")) + self.report_check.append(t1) + + t1 = (KEY_DISP_ALLOW_SHEAR, ' ', + cl_8_2_1_2_shear_check(round(self.result_shear, 2), round(0.6 * self.result_shear, 2), + self.result_high_shear, self.load.shear_force * 10 ** -3), + get_pass_fail(self.load.shear_force * 10 ** -3, round(0.6 * self.result_shear, 2), + relation="Warn", M1=self.result_high_shear)) + self.report_check.append(t1) + + # t1 = ('SubSection', 'Moment Strength Results', '|p{4cm}|p{4cm}|p{6.5cm}|p{1.5cm}|') + + t1 = ('SubSection', 'Moment Strength Results', '|p{4cm}|p{1.5cm}|p{9cm}|p{1.5cm}|') + self.report_check.append(t1) + if self.design_type == KEY_DISP_DESIGN_TYPE_FLEXURE: + if self.result_high_shear: + t1 = (KEY_DISP_Bending_STRENGTH_MOMENT, self.load.moment * 10 ** -6, + cl_9_2_2_combine_shear_bending_md_init( + self.section_property.elast_sec_mod_z, + self.section_property.plast_sec_mod_z, + self.material_property.fy, self.support, + self.gamma_m0, round(self.result_betab, 2), + round(self.result_Md * 10 ** -6, 2), self.result_section_class + ), + ' ') + self.report_check.append(t1) + t1 = (KEY_DISP_PLASTIC_STRENGTH_MOMENT, ' ', + cl_9_2_2_combine_shear_bending_mfd( + self.section_property.plast_sec_mod_z, + self.section_property.depth, + self.section_property.web_thickness, + self.material_property.fy, + self.gamma_m0, + round(self.result_mfd * 10 ** -6, 2)), + ' ') + self.report_check.append(t1) + + # temp = cl_8_2_1_2_plastic_moment_capacity_member(self.result_betab, + # self.section_property.plast_sec_mod_z, + # self.material_property.fy, self.gamma_m0, + # round(self.result_bending, 2)) + # print('tempt',temp) + + t1 = (KEY_DISP_DESIGN_STRENGTH_MOMENT, self.load.moment * 10 ** -6, + cl_9_2_2_combine_shear_bending(round(self.result_bending, 2), + self.section_property.elast_sec_mod_z, + self.material_property.fy, self.result_section_class, + self.load.shear_force * 10 ** -3, round(self.result_shear, 2), + self.gamma_m0, round(self.result_beta_reduced, 2), + round(self.result_Md * 10 ** -6, 2), + round(self.result_mfd * 10 ** -6, 2)), + get_pass_fail(self.load.moment * 10 ** -6, round(self.result_bending, 2), relation="lesser")) + self.report_check.append(t1) + + else: + t1 = (KEY_DISP_DESIGN_STRENGTH_MOMENT, self.load.moment * 10 ** -6, + cl_8_2_1_2_moment_capacity_member(round(self.result_betab, 3), + self.section_property.plast_sec_mod_z, + self.material_property.fy, self.gamma_m0, + round(self.result_bending, 2), + self.section_property.elast_sec_mod_z, + self.result_section_class, self.support), + get_pass_fail(self.load.moment * 10 ** -6, round(self.result_bending, 2), relation="lesser")) + self.report_check.append(t1) + elif self.design_type == KEY_DISP_DESIGN_TYPE2_FLEXURE: + # KEY_DISP_Elastic_CM_latex + t1 = (KEY_DISP_Elastic_CM_latex, ' ', + cl_8_2_2_1_Mcr( + self.result_mcr, + self.material_property.modulus_of_elasticity, + self.section_property.mom_inertia_y, + self.result_eff_len, self.material_property.modulus_of_elasticity / (2 * 1.3), + self.section_property.It, self.section_property.Iw + # round(self.result_Md * 10 ** -6, 2), self.result_section_class + ), + ' ') + self.report_check.append(t1) + + # t1 = (KEY_DISP_I_eff_latex + '($mm^4$)', ' ', + # cl_8_7_3_Ieff_web_check(self.bearing_length, self.section_property.web_thickness, + # round(self.result_bcI_eff,2)), + # ' ') + # self.report_check.append(t1) + + # t1 = (KEY_DISP_A_eff_latex+ '($mm^2$)', ' ', + # cl_8_7_3_Aeff_web_check(self.bearing_length, self.section_property.web_thickness, + # self.result_bcA_eff), + # ' ') + # self.report_check.append(t1) + + # t1 = (KEY_DISP_r_eff_latex+ '(mm)', ' ', + # cl_8_7_3_reff_web_check(round(self.result_bcr_eff,2), round(self.result_bcI_eff,2), + # self.result_bcA_eff), + # ' ') + # self.report_check.append(t1) + + t1 = (KEY_DISP_SLENDER + '($\lambda_{LT}$)', ' ', + cl_8_2_2_slenderness(round(self.result_betab, 2), self.section_property.elast_sec_mod_z, + self.section_property.plast_sec_mod_z, self.result_mcr, + self.material_property.fy, + self.result_nd_esr_lt), + ' ') + self.report_check.append(t1) + + # # t1 = (KEY_DISP_SLENDER, ' ', + # # cl_8_7_1_5_slenderness(round(self.result_bcr_eff, 2), round(self.result_eff_d, 2), + # # self.result_eff_sr), + # # ' ') + # # self.report_check.append(t1) + + # t1 = (KEY_DISP_BUCKLING_CURVE_ZZ, ' ', + # cl_8_7_1_5_buckling_curve(), + # ' ') + # self.report_check.append(t1) + + t1 = (KEY_DISP_IMPERFECTION_FACTOR_ZZ + r'($\alpha_{LT}$)', ' ', + cl_8_7_1_5_imperfection_factor(self.result_IF_lt), + ' ') + self.report_check.append(t1) + + # t1 = (KEY_DISP_EULER_BUCKLING_STRESS_ZZ, ' ', + # cl_8_7_1_5_buckling_stress(self.section_property.modulus_of_elasticity,self.result_eff_sr,self.result_ebs), + # ' ') + # self.report_check.append(t1) + + t1 = ('$\phi_{LT}$', ' ', + cl_8_2_2_phi(self.result_IF_lt, self.result_nd_esr_lt, self.result_phi_lt), + ' ') + self.report_check.append(t1) + + t1 = ('Bending Compressive stress($N/mm^2$)', ' ', + cl_8_2_2_Bending_Compressive(self.material_property.fy, self.gamma_m0, self.result_nd_esr_lt, + self.result_phi_lt, self.result_fcd__lt), + ' ') + self.report_check.append(t1) + + # t1 = (KEY_DISP_BUCKLING_STRENGTH, self.load.shear_force * 10 ** -3, + # cl_7_1_2_design_compressive_strength(self.result_capacity,round(( + # self.bearing_length + self.section_property.depth / 2) * self.section_property.web_thickness,2), self.result_fcd,self.load.shear_force * 10 ** -3), + # get_pass_fail(self.load.shear_force * 10 ** -3, round(self.result_capacity, 2), relation="leq")) + # self.report_check.append(t1) + + if self.result_high_shear: + t1 = (KEY_DISP_LTB_Bending_STRENGTH_MOMENT, self.load.moment * 10 ** -6, + cl_9_2_2_combine_shear_bending_md_init( + self.section_property.elast_sec_mod_z, + self.section_property.plast_sec_mod_z, + self.material_property.fy, self.support, + self.gamma_m0, round(self.result_betab, 2), + round(self.result_Md * 10 ** -6, 2), self.result_section_class + ), + ' ') + self.report_check.append(t1) + t1 = (KEY_DISP_PLASTIC_STRENGTH_MOMENT, ' ', + cl_9_2_2_combine_shear_bending_mfd( + self.section_property.plast_sec_mod_z, + self.section_property.depth, + self.section_property.web_thickness, + self.material_property.fy, + self.gamma_m0, + round(self.result_mfd * 10 ** -6, 2)), + ' ') + self.report_check.append(t1) + + # temp = cl_8_2_1_2_plastic_moment_capacity_member(self.result_betab, + # self.section_property.plast_sec_mod_z, + # self.material_property.fy, self.gamma_m0, + # round(self.result_bending, 2)) + # print('tempt',temp) + t1 = (KEY_DISP_REDUCE_STRENGTH_MOMENT, self.load.moment * 10 ** -6, + cl_9_2_2_combine_shear_bending(round(self.result_bending, 2), + self.section_property.elast_sec_mod_z, + self.material_property.fy, self.result_section_class, + self.load.shear_force * 10 ** -3, round(self.result_shear, 2), + self.gamma_m0, round(self.result_betab, 2), + round(self.result_Md * 10 ** -6, 2), + round(self.result_mfd * 10 ** -6, 2)), + get_pass_fail(self.load.moment * 10 ** -6, round(self.result_bending, 2), relation="lesser")) + self.report_check.append(t1) + + else: + t1 = ('Moment Strength (kNm)', self.load.moment * 10 ** -6, + cl_8_2_2_moment_capacity_member(round(self.result_betab, 2), + self.section_property.plast_sec_mod_z, + self.material_property.fy, self.gamma_m0, + round(self.result_bending, 2), + self.section_property.elast_sec_mod_z, + self.result_section_class, self.support), + get_pass_fail(self.load.moment * 10 ** -6, round(self.result_bending, 2), relation="lesser")) + self.report_check.append(t1) + + if self.result_buckling_crippling: + t1 = ('SubSection', 'Web Buckling Checks', '|p{4cm}|p{2 cm}|p{7cm}|p{3 cm}|') + self.report_check.append(t1) + + t1 = (KEY_DISP_I_eff_latex + '($mm^4$)', ' ', + cl_8_7_3_Ieff_web_check(self.bearing_length, self.section_property.web_thickness, + round(self.result_bcI_eff, 2)), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_A_eff_latex + '($mm^2$)', ' ', + cl_8_7_3_Aeff_web_check(self.bearing_length, self.section_property.web_thickness, + self.result_bcA_eff), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_r_eff_latex + '(mm)', ' ', + cl_8_7_3_reff_web_check(round(self.result_bcr_eff, 2), round(self.result_bcI_eff, 2), + self.result_bcA_eff), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_SLENDER + '($\lambda$)', ' ', + cl_8_7_1_5_slenderness(round(self.result_bcr_eff, 2), round(self.result_eff_d, 2), + self.result_eff_sr), + ' ') + self.report_check.append(t1) + + # t1 = (KEY_DISP_SLENDER, ' ', + # cl_8_7_1_5_slenderness(round(self.result_bcr_eff, 2), round(self.result_eff_d, 2), + # self.result_eff_sr), + # ' ') + # self.report_check.append(t1) + + t1 = (KEY_DISP_BUCKLING_CURVE_ZZ, ' ', + cl_8_7_1_5_buckling_curve(), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_IMPERFECTION_FACTOR_ZZ + r'($\alpha$)', ' ', + cl_8_7_1_5_imperfection_factor(self.result_IF), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_EULER_BUCKLING_STRESS_ZZ, ' ', + cl_8_7_1_5_buckling_stress(self.section_property.modulus_of_elasticity, self.result_eff_sr, + self.result_ebs), + ' ') + self.report_check.append(t1) + + t1 = ('$\phi$', ' ', + cl_8_7_1_5_phi(0.49, self.result_eff_sr, self.result_phi_zz), + ' ') + self.report_check.append(t1) + + t1 = ('Buckling stress($N/mm^2$)', ' ', + cl_8_7_1_5_Buckling(self.material_property.fy, self.gamma_m0, self.result_eff_sr, + self.result_phi_zz, self.result_fcd_2, self.result_fcd), + ' ') + self.report_check.append(t1) + + t1 = (KEY_DISP_BUCKLING_STRENGTH, self.load.shear_force * 10 ** -3, + cl_7_1_2_design_compressive_strength(self.result_capacity, round(( + self.bearing_length + self.section_property.depth / 2) * self.section_property.web_thickness, + 2), self.result_fcd, + self.load.shear_force * 10 ** -3), + get_pass_fail(self.load.shear_force * 10 ** -3, round(self.result_capacity, 2), relation="leq")) + self.report_check.append(t1) + + t1 = ('SubSection', 'Web Bearing Checks', '|p{4cm}|p{2 cm}|p{7cm}|p{3 cm}|') + self.report_check.append(t1) + + t1 = ('Bearing Strength(kN)', self.load.shear_force * 10 ** -3, + cl_8_7_4_Bearing_stiffener_check(self.bearing_length, round(2.5 * ( + self.section_property.root_radius + self.section_property.flange_thickness), 2), + self.section_property.web_thickness, + self.material_property.fy, self.gamma_m0, + round(self.result_crippling, 2), + self.section_property.root_radius, + self.section_property.flange_thickness), + get_pass_fail(self.load.shear_force * 10 ** -3, round(self.result_crippling, 2), relation="leq")) + + self.report_check.append(t1) + + t1 = ('SubSection', 'Utilization', '|p{4cm}|p{2 cm}|p{7cm}|p{3 cm}|') + self.report_check.append(t1) + # TODO + if self.result_buckling_crippling: + t1 = (KEY_DISP_Utilization_Ratio, 1.0, + Utilization_Ratio_Latex(self.load.shear_force * 10 ** -3, round(self.result_shear, 2), + self.load.moment * 10 ** -6, round(self.result_bending, 2), + self.result_UR, type=2, Pd=self.result_capacity, + fw=self.result_crippling), + get_pass_fail(1.0, self.result_UR, relation="geq")) + else: + t1 = (KEY_DISP_Utilization_Ratio, 1.0, + Utilization_Ratio_Latex(self.load.shear_force * 10 ** -3, round(self.result_shear, 2), + self.load.moment * 10 ** -6, round(self.result_bending, 2), + self.result_UR), + get_pass_fail(1.0, self.result_UR, relation="geq")) + self.report_check.append(t1) + # if self.design_type == KEY_DISP_DESIGN_TYPE2_FLEXURE: + # t1 = ('SubSection', 'Lateral Torsional Buckling Checks', '|p{4cm}|p{2 cm}|p{7cm}|p{3 cm}|') + # self.report_check.append(t1) + # t1 = (KEY_DISP_A_eff_latex + '(mm^2)', ' ', + # cl_8_7_3_Aeff_web_check(self.bearing_length, self.section_property.web_thickness, + # self.result_bcA_eff), + # ' ') + # self.report_check.append(t1) + # if self.latex_tension_zone == True : + # t1 = (KEY_DISP_TENSION_HOLES, ' ', + # sectional_area_change(self.result_effective_area, self.section_property.area, + # self.effective_area_factor), + # ' ') + # self.report_check.append(t1) + + # else: + # t1 = (KEY_DISP_ALLOW_SHEAR, self.load.shear_force, + # allow_shear_capacity(round(self.result_shear, 2), round(0.6 * self.result_shear, 2)), + # get_pass_fail(self.load.shear_force)) + # self.report_check.append(t1) + + # self.h = (self.beam_D - (2 * self.beam_tf)) + # + # 1.1 Input sections display + # t1 = ('SubSection', 'List of Input Sections',self.sec_list), + # self.report_check.append(t1) + # + # # 2.2 CHECK: Buckling Class - Compatibility Check + # t1 = ('SubSection', 'Buckling Class - Compatibility Check', '|p{4cm}|p{3.5cm}|p{6.5cm}|p{2cm}|') + # self.report_check.append(t1) + # + # t1 = ("Section Class ", comp_column_class_section_check_required(self.result_section_class, self.h, self.bf), + # comp_column_class_section_check_provided(self.bucklingclass, self.h, self.bf, self.tf, self.var_h_bf), + # 'Compatible') # if self.bc_compatibility_status is True else 'Not compatible') + # self.report_check.append(t1) + + # t1 = ("h/bf , tf ", comp_column_class_section_check_required(self.bucklingclass, self.h, self.bf), + # comp_column_class_section_check_provided(self.bucklingclass, self.h, self.bf, self.tf, self.var_h_bf), + # 'Compatible') # if self.bc_compatibility_status is True else 'Not compatible') + # self.report_check.append(t1) + # + # # 2.3 CHECK: Cross-section classification + # t1 = ('SubSection', 'Cross-section classification', '|p{4.5cm}|p{3cm}|p{6.5cm}|p{1.5cm}|') + # self.report_check.append(t1) + # + # t1 = ("b/tf and d/tw ", cross_section_classification_required(self.section), + # cross_section_classification_provided(self.tf, self.b1, self.epsilon, self.section, self.b1_tf, + # self.d1_tw, self.ep1, self.ep2, self.ep3, self.ep4), + # 'b = bf / 2,d = h – 2 ( T + R1),έ = (250 / Fy )^0.5,Compatible') # if self.bc_compatibility_status is True else 'Not compatible') + # self.report_check.append(t1) + # + # # 2.4 CHECK : Member Check + # t1 = ("Slenderness", cl_7_2_2_slenderness_required(self.KL, self.ry, self.lamba), + # cl_7_2_2_slenderness_provided(self.KL, self.ry, self.lamba), 'PASS') + # self.report_check.append(t1) + # + # t1 = ( + # "Design Compressive stress (fcd)", cl_7_1_2_1_fcd_check_required(self.gamma_mo, self.f_y, self.f_y_gamma_mo), + # cl_7_1_2_1_fcd_check_provided(self.facd), 'PASS') + # self.report_check.append(t1) + # + # t1 = ("Design Compressive strength (Pd)", cl_7_1_2_design_comp_strength_required(self.axial), + # cl_7_1_2_design_comp_strength_provided(self.Aeff, self.facd, self.A_eff_facd), "PASS") + # self.report_check.append(t1) + # + # t1 = ('', '', '', '') + # self.report_check.append(t1) + else: + self.report_input = \ + { # KEY_MAIN_MODULE: self.mainmodule, + KEY_MODULE: self.module, # "Axial load on column " + KEY_DISP_SHEAR + '*': self.load.shear_force * 10 ** -3, + KEY_DISP_BEAM_MOMENT_Latex + '*': self.load.moment * 10 ** -6, + KEY_DISP_LENGTH_BEAM: self.length, + KEY_DISP_SEC_PROFILE: self.sec_profile, + KEY_DISP_SECSIZE: str(self.sec_list), + KEY_MATERIAL: self.material, + # "Failed Section Details": self.report_column, + KEY_BEAM_SUPP_TYPE: self.latex_design_type, + } + self.report_input.update({ + KEY_DISP_SUPPORT: self.support, + KEY_DISP_ULTIMATE_STRENGTH_REPORT: self.material_property.fu, + KEY_DISP_YIELD_STRENGTH_REPORT: self.material_property.fy, + "End Conditions - " + str(self.support): "TITLE", + }) + # if self.Latex_length == 'NA': + if self.support == KEY_DISP_SUPPORT1: + self.report_input.update({ + DISP_TORSIONAL_RES: self.Torsional_res, + DISP_WARPING_RES: self.Warping}) + else: + self.report_input.update({ + DISP_SUPPORT_RES: self.Support, + DISP_TOP_RES: self.Top}) + self.report_input.update({ + "Design Preference": "TITLE", + KEY_DISP_EFFECTIVE_AREA_PARA: self.effective_area_factor, + KEY_DISP_CLASS: self.allow_class, + KEY_DISP_LOAD: self.Loading, + KEY_DISPP_LENGTH_OVERWRITE: self.latex_efp, + KEY_DISP_BEARING_LENGTH + ' (mm)': self.bearing_length, + + }) + # if self.latex_design_type == VALUES_SUPP_TYPE_temp[0] and self.result_web_buckling_check: + # self.report_input.update({ + # KEY_ShearBuckling: self.support_cndition_shear_buckling + # }) + # self.report_input.update({ + # # KEY_DISP_SEC_PROFILE: self.sec_profile, + # "I Section - Mechanical Properties": "TITLE", + # }) + self.report_input.update() + self.report_check = [] + + t1 = ('Selected', 'All Members Failed', '|p{5cm}|p{2cm}|p{2cm}|p{2cm}|p{4cm}|') + self.report_check.append(t1) + + t1 = ('SubSection', 'Plastic Section Modulus', '|p{4cm}|p{1.5cm}|p{2.5cm}|p{8cm}|') + self.report_check.append(t1) + t1 = ('Plastic Section Modulus($mm^3$)', round(self.Zp_req, 2), + ' ', + 'Select Sections with atleast required Plastic Section Modulus ') + self.report_check.append(t1) + print(sys.path[0]) + rel_path = str(sys.path[0]) + rel_path = rel_path.replace("\\", "/") + fname_no_ext = popup_summary['filename'] + CreateLatex.save_latex(CreateLatex(), self.report_input, self.report_check, popup_summary, fname_no_ext, + rel_path, [], '', module=self.module) # + + + diff --git a/src/osdag/fuse_trace_wrapper.py b/src/osdag/fuse_trace_wrapper.py new file mode 100644 index 000000000..49af7a5d0 --- /dev/null +++ b/src/osdag/fuse_trace_wrapper.py @@ -0,0 +1,57 @@ +import sys +import os +import OCC.Core.BRepAlgoAPI +from functools import wraps + +# File to save the trace output +TRACE_OUTPUT_FILE = "trace_output_fuse.txt" + +# Path to ignore (conda environment directory) +CONDA_PATH = os.getenv('CONDA_PREFIX', '') + +# Backup original function/class +original_fuse_class = OCC.Core.BRepAlgoAPI.BRepAlgoAPI_Fuse + +# Create a wrapper class that inherits from the original +class TracedFuseClass(original_fuse_class): + def __init__(self, *args, **kwargs): + # Get caller information + frame = sys._getframe(1) + function_name = frame.f_code.co_name + line_number = frame.f_lineno + file_path = frame.f_globals.get("__file__", "") + + # Ignore calls from conda environment files + if CONDA_PATH and file_path.startswith(CONDA_PATH): + super().__init__(*args, **kwargs) + return + + # Call original constructor + super().__init__(*args, **kwargs) + + # Log details without trying to stringify self + with open(TRACE_OUTPUT_FILE, "a", encoding="utf-8") as f: + f.write(f"Function Call: BRepAlgoAPI_Fuse\n") + f.write(f" Called from: {function_name}, line {line_number}, file: {file_path}\n") + f.write(f" Arguments count: {len(args)}\n") + # Safely log argument types without trying to fully stringify them + arg_types = [type(arg).__name__ for arg in args] + f.write(f" Argument types: {arg_types}\n\n") + +# Replace the original class with our traced version +OCC.Core.BRepAlgoAPI.BRepAlgoAPI_Fuse = TracedFuseClass + +# Clear output file before starting +with open(TRACE_OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("Trace Log:\n\n") + +# Let the original script continue execution + +# Import and execute the target script that would eventually use BoltedCAD.py +script_path = "osdag/osdagMainPage.py" +with open(script_path) as f: + code = f.read() + exec(code) + +# Restore original class after execution +OCC.Core.BRepAlgoAPI.BRepAlgoAPI_Fuse = original_fuse_class \ No newline at end of file diff --git a/src/osdag/gui/BC2Cendplate.py b/src/osdag/gui/BC2Cendplate.py new file mode 100644 index 000000000..9f8d63924 --- /dev/null +++ b/src/osdag/gui/BC2Cendplate.py @@ -0,0 +1,638 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene,QGraphicsRectItem) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont , QColor +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class BC2CEndPlate(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + print(main) + if main: + self.flag=main[1] + main=main[0] + super().__init__() + self.connection = connection_obj + data=main.output_values(main,True) + + print(type(main)) + dict1={i[0] : i[3] for i in data} + for i in dict1: + print(f'{i} : {dict1[i]}') + self.plate_width=dict1['Plate.Height'] + self.plate_length=dict1['Plate.Length'] + self.stiffener_length=dict1['Stiffener.Width'] + self.stiffener_thickness=dict1['Stiffener.Thickness'] + self.web_thickness=main.section.web_thickness + self.flange_thickness=main.section.flange_thickness + self.webdetail_width=self.plate_width-2*self.stiffener_length + self.webdetail_len=self.plate_length + self.hole_dia=dict1['Bolt.Diameter'] + webspacing=dict1['Bolt.web_bolts'][1] + flangespacing=dict1['Bolt.flange_bolts'][1] + flangespacing=flangespacing(main,True) + # print(webspacing) + webspacing=webspacing(main,True) + print(webspacing) + # for i in webspacing: + # print(i) + dict2={i[1] : i[3] for i in webspacing} + for i in dict2: + print(f'{i} : {dict2[i]}') + self.web_bolts=dict2['No. of Bolts (along web)'] + self.pitch1,self.pitch2,self.pitch3,self.pitch4=0,0,0,0 + if 'Pitch 1-2' in dict2: + self.pitch1=dict2['Pitch 1-2'] + if 'Pitch 2-3' in dict2: + self.pitch2=dict2['Pitch 2-3'] + if 'Pitch 3-4' in dict2: + self.pitch3=dict2['Pitch 3-4'] + if 'Pitch 4-5' in dict2: + self.pitch4=dict2['Pitch 4-5'] + for i in flangespacing: + print(i) + dict3={i[0] : i[3] for i in flangespacing} + self.flangeend,self.boltoneside,self.flangetotal,self.pitchflange=0,0,0,0 + if 'Bolt.EndDist' in dict3: + self.flangeend=dict3['Bolt.EndDist'] + if 'ColumnEndPlate.nbf' in dict3: + self.boltoneside=dict3['ColumnEndPlate.nbf'] + if 'ColumnEndPlate.nbftotal' in dict3: + self.flangetotal=dict3['ColumnEndPlate.nbftotal'] + if 'ColumnEndPlate.p2_flange' in dict3: + self.flangepitch=dict3['ColumnEndPlate.p2_flange'] + print(f' Flange End Distance : {self.flangeend} , TotalBolt : {self.flangetotal}') + self.web_end=dict2['End Distance (mm)'] + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + print(f""" + Plate Width : {self.plate_width} + Plate Length : {self.plate_length} + Stiffener Length (Width) : {self.stiffener_length} + Stiffener Thickness : {self.stiffener_thickness} + Web Thickness : {self.web_thickness} + Flange Thickness : {self.flange_thickness} + Web Detail Length : {self.webdetail_len} + Web Detail Width : {self.webdetail_width} + """) + + self.setGeometry(100, 100, 1200, 900) + # Step 1: Create a central widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # Step 2: Create main layout + main_layout = QHBoxLayout() + central_widget.setLayout(main_layout) + + # Step 3: Left panel for selected labels only + left_panel = QWidget() + left_layout = QVBoxLayout() + left_panel.setLayout(left_layout) + + # Only display selected keys + keys_to_display = [ + 'Plate Length', + 'Plate Width', + + ] + + # Define the corresponding values for the keys (assumes self. are already set) + values_to_display = { + 'Plate Length': self.plate_length, + 'Plate Width': self.plate_width, + + } + + + for key in keys_to_display: + if key in values_to_display: + label = QLabel(f"{key}: {values_to_display[key]}") + left_layout.addWidget(label) + # Step 4: Graphics view and scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Background and test shape (optional) + self.scene.setBackgroundBrush(Qt.white) + + # Step 5: Add to main layout + main_layout.addWidget(self.view, stretch=2) + main_layout.addWidget(left_panel, stretch=1) + + self.fontsize=10 + self.arrowsize=10 + + if self.plate_length>1200 or self.plate_width>1200: + self.fontsize=5 + self.arrowsize=5 + elif self.plate_length>600 or self.plate_width>600: + self.fontsize=10 + self.arrowsize=10 + self.createDrawing() + if self.plate_length>1200 or self.plate_width>1200: + self.view.resetTransform() + self.view.scale(0.4, 0.4) + elif self.plate_length>600 or self.plate_width>600: + self.view.resetTransform() + self.view.scale(0.75, 0.75) + + # Step 6: Call parameter extraction and drawing + + + def createDrawing(self): + try: + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + stiff_len=self.stiffener_length + stiff_thick=self.stiffener_thickness + web_thick=self.web_thickness + flange_thick=self.flange_thickness + webdetailinglen=self.webdetail_len + webdetailingwidth=self.webdetail_width + web_bolts=self.web_bolts + web_end=self.web_end + pitch1=self.pitch1 + pitch2=self.pitch2 + pitch3=self.pitch3 + pitch4=self.pitch4 + hole_dia=self.hole_dia + except (TypeError, ValueError): + print("Invalid plate dimensions") + return + if self.flag==0: + rect = QRectF(0, 0, webdetailinglen, webdetailingwidth) + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(Qt.black) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush(Qt.NoBrush)) + + # Add rectangle to the scene + self.scene.addItem(rect_item) + # Extract parameters + outline_pen = QPen(Qt.black) + outline_pen.setWidth(2) + + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, webdetailinglen, webdetailingwidth)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(Qt.white)) + self.scene.addItem(rect_item) + # === Center of the base plate === + center_x = webdetailinglen / 2 + center_y = webdetailingwidth / 2 + self.addHorizontalDimension( + 0, -30, # x1 at left edge, y above plate + webdetailinglen, -30, # x2 at right edge, same y + f"{webdetailinglen} mm", pen + ) + + # Vertical dimension for plate width (to the left of the plate) + self.addVerticalDimension( + webdetailinglen+30, 0, # x left of plate, y1 at top + webdetailinglen+30, webdetailingwidth, # x2 same, y2 at bottom + f"{webdetailingwidth} mm", pen + ) + line_pen = QPen(QColor("orange")) + line_pen.setWidth(2) + + # Line at y = 0 (full length) + line_top = self.scene.addLine( + 0, 0, # Start point (x=0, y=0) + webdetailinglen, 0, # End point (x=plate_length, y=0) + line_pen + ) + + # Lines at y = flange_thickness + # First line: from x = 0 to center_x - web_thickness / 2 + line_flange_left = self.scene.addLine( + 0, flange_thick, + center_x - web_thick / 2, flange_thick, + line_pen + ) + + # Second line: from x = center_x + web_thickness / 2 to x = plate_length + line_flange_right = self.scene.addLine( + center_x + web_thick / 2, flange_thick, + webdetailinglen, flange_thick, + line_pen + ) + line_left_vertical = self.scene.addLine( + 0, 0, # x = 0, y = 0 + 0, flange_thick, # x = 0, y = flange_thickness + line_pen + ) + + # Right vertical line at x = plate_length + line_right_vertical = self.scene.addLine( + plate_length, 0, # x = plate_length, y = 0 + webdetailinglen, flange_thick, # x = plate_length, y = flange_thickness + line_pen + ) + # === Bottom side === + + # Line at y = webdetailingwidth (full length) + line_bottom = self.scene.addLine( + 0, webdetailingwidth, + webdetailinglen, webdetailingwidth, + line_pen + ) + + # Lines at y = webdetailingwidth - flange_thick + # First line: from x = 0 to center_x - web_thick / 2 + line_bottom_flange_left = self.scene.addLine( + 0, webdetailingwidth - flange_thick, + center_x - web_thick / 2, webdetailingwidth - flange_thick, + line_pen + ) + + # Second line: from x = center_x + web_thick / 2 to x = webdetailinglen + line_bottom_flange_right = self.scene.addLine( + center_x + web_thick / 2, webdetailingwidth - flange_thick, + webdetailinglen, webdetailingwidth - flange_thick, + line_pen + ) + + # Vertical line at x = 0, from y = webdetailingwidth - flange_thick to y = webdetailingwidth + line_bottom_left_vertical = self.scene.addLine( + 0, webdetailingwidth - flange_thick, + 0, webdetailingwidth, + line_pen + ) + + # Vertical line at x = webdetailinglen, from y = webdetailingwidth - flange_thick to y = webdetailingwidth + line_bottom_right_vertical = self.scene.addLine( + webdetailinglen, webdetailingwidth - flange_thick, + webdetailinglen, webdetailingwidth, + line_pen + ) + # === Web vertical lines === + + # Left web vertical line at x = center_x - web_thick / 2 + line_web_left_vertical = self.scene.addLine( + center_x - web_thick / 2, flange_thick, + center_x - web_thick / 2, webdetailingwidth - flange_thick, + line_pen + ) + + # Right web vertical line at x = center_x + web_thick / 2 + line_web_right_vertical = self.scene.addLine( + center_x + web_thick / 2, flange_thick, + center_x + web_thick / 2, webdetailingwidth - flange_thick, + line_pen + ) + bolt_pen = QPen(QColor("blue")) + bolt_pen.setWidth(2) + bolt_brush = QBrush(Qt.NoBrush) + + # Number of rows = web_bolts / 2 + num_rows = int(web_bolts / 2) + + # X positions of columns + x_left = center_x - web_thick / 2 - web_end + x_right = center_x + web_thick / 2 + web_end + + # Starting Y position + y_pos = flange_thick + web_end + + # Pitch list to cycle through + pitch_list = [pitch1, pitch2, pitch3, pitch4] + + # Draw bolts row by row + for row in range(num_rows): + # Draw left bolt + self.scene.addEllipse( + x_left - hole_dia / 2, # X center aligned + y_pos - hole_dia / 2, # Y center aligned + hole_dia, + hole_dia, + bolt_pen, + bolt_brush + ) + + # Draw right bolt + self.scene.addEllipse( + x_right - hole_dia / 2, + y_pos - hole_dia / 2, + hole_dia, + hole_dia, + bolt_pen, + bolt_brush + ) + + # Increment Y position by next pitch + pitch_index = row % len(pitch_list) # Cycle through pitches + y_pos += pitch_list[pitch_index] + self.addHorizontalDimension( + center_x + web_thick / 2, webdetailingwidth+20, # x1, y1 + center_x + web_thick / 2 + web_end, webdetailingwidth+20, # x2, y2 + f"{web_end} mm", # Dimension label + pen # Use the pen you already have (black or any color) + ) + y_temp=flange_thick+web_end+hole_dia+5 + self.addHorizontalDimension( + center_x + web_thick / 2+web_end-hole_dia/2, y_temp, # x1, y1 + center_x + web_thick / 2 + web_end+hole_dia/2, y_temp, # x2, y2 + f"{hole_dia} mm", # Dimension label + pen # Use the pen you already have (black or any color) + ) + x_dim = -20 + + # Starting Y + y_current = flange_thick + web_end + self.addVerticalDimension( + x_dim, y_current-web_end, # x1, y1 + x_dim, y_current, # x2, y2 + f"{web_end} mm", # Dimension label + pen # Use your dimension pen (black or any color) + ) + # List of pitches + pitch_list = [pitch1, pitch2, pitch3, pitch4] + + # Iterate over pitches + for pitch in pitch_list: + if pitch == 0: + break # Stop if pitch is 0 + + y_next = y_current + pitch + + # Add vertical dimension for this pitch + self.addVerticalDimension( + x_dim, y_current, # x1, y1 + x_dim, y_next, # x2, y2 + f"{pitch} mm", # Dimension label + pen # Use your dimension pen (black or any color) + ) + + # Move to next position + y_current = y_next + else: + flangelen=plate_length + flangewidth=plate_width/2 + webdetailingwidth=flangewidth + + rect = QRectF(0, 0, flangelen, flangewidth) + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(Qt.black) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush(Qt.NoBrush)) + + # Add rectangle to the scene + self.scene.addItem(rect_item) + # Extract parameters + outline_pen = QPen(Qt.black) + outline_pen.setWidth(2) + + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, flangelen, flangewidth)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(Qt.white)) + self.scene.addItem(rect_item) + # === Center of the base plate === + center_x = flangelen / 2 + center_y = flangewidth / 2 + self.addHorizontalDimension( + 0, -30, # x1 at left edge, y above plate + flangelen, -30, # x2 at right edge, same y + f"{flangelen} mm", pen + ) + + # Vertical dimension for plate width (to the left of the plate) + self.addVerticalDimension( + flangelen+30, 0, # x left of plate, y1 at top + flangelen+30, flangewidth, # x2 same, y2 at bottom + f"{flangewidth} mm", pen + ) + stiffener_rect = QRectF( + center_x - stiff_thick / 2, # x1 + 0, # y1 + stiff_thick, # width + stiff_len # height + ) + stiffener_item = QGraphicsRectItem(stiffener_rect) + stiffener_item.setPen(QPen(Qt.black)) + stiffener_item.setBrush(QBrush(Qt.blue)) + self.scene.addItem(stiffener_item) + line_pen = QPen(QColor("orange")) + line_pen.setWidth(2) + line_top = self.scene.addLine( + 0, stiff_len, # Start point (x=0, y=stiff_len) + webdetailinglen, stiff_len, # End point (x=plate_length, y=stiff_len) + line_pen + ) + + # Lines at y = stiff_len + flange_thickness + # First line: from x = 0 to center_x - web_thickness / 2 + line_flange_left = self.scene.addLine( + 0, stiff_len + flange_thick, + center_x - web_thick / 2, stiff_len + flange_thick, + line_pen + ) + + # Second line: from x = center_x + web_thickness / 2 to x = plate_length + line_flange_right = self.scene.addLine( + center_x + web_thick / 2, stiff_len + flange_thick, + webdetailinglen, stiff_len + flange_thick, + line_pen + ) + + # Left vertical line at x = 0 + line_left_vertical = self.scene.addLine( + 0, stiff_len, + 0, stiff_len + flange_thick, + line_pen + ) + + # Right vertical line at x = plate_length + line_right_vertical = self.scene.addLine( + plate_length, stiff_len, + plate_length, stiff_len + flange_thick, + line_pen + ) + stiff_line_vertical=self.scene.addLine( + center_x-web_thick/2,stiff_len+flange_thick, + center_x-web_thick/2,webdetailingwidth,line_pen + ) + stiff_line_vertical=self.scene.addLine( + center_x+web_thick/2,stiff_len+flange_thick, + center_x+web_thick/2,webdetailingwidth,line_pen + ) + totalbolts=self.flangetotal/2 + flangeend=self.flangeend + cols=self.boltoneside*2 + line_pen=QPen(Qt.blue) + if stiff_len>0 and totalbolts>2 : + y_pos = flangeend # You need to define this depending on your layout logic + + # Calculate center + center_x = self.plate_length / 2 + + # Calculate bolt positions + left_bolt_x = center_x-web_thick/2-flangeend + right_bolt_x = center_x+web_thick/2+flangeend + + # Add bolts to scene (assuming addEllipse represents bolts) + bolt_radius = hole_dia/2 # or whatever radius you use + self.scene.addEllipse(left_bolt_x - bolt_radius, y_pos - bolt_radius, + 2 * bolt_radius, 2 * bolt_radius, line_pen) + self.scene.addEllipse(right_bolt_x - bolt_radius, y_pos - bolt_radius, + 2 * bolt_radius, 2 * bolt_radius, line_pen) + totalbolts-=2 + num_rows = int(web_bolts // 4) + # X positions of columns + x_left = center_x - web_thick / 2 - web_end + x_right = center_x + web_thick / 2 + web_end + + # Starting Y position + y_pos = flange_thick + web_end+stiff_len + + # Pitch list to cycle through + pitch_list = [pitch1, pitch2, pitch3, pitch4] + + # Draw bolts row by row + for row in range(num_rows): + # Draw left bolt + self.scene.addEllipse( + x_left - hole_dia / 2, # X center aligned + y_pos - hole_dia / 2, # Y center aligned + hole_dia, + hole_dia, + line_pen + ) + + # Draw right bolt + self.scene.addEllipse( + x_right - hole_dia / 2, + y_pos - hole_dia / 2, + hole_dia, + hole_dia, + line_pen + ) + + # Increment Y position by next pitch + pitch_index = row % len(pitch_list) # Cycle through pitches + y_pos += pitch_list[pitch_index] + self.addHorizontalDimension( + center_x + web_thick / 2, webdetailingwidth+20, # x1, y1 + center_x + web_thick / 2 + web_end, webdetailingwidth+20, # x2, y2 + f"{web_end} mm", # Dimension label + pen # Use the pen you already have (black or any color) + ) + y_temp=flange_thick+web_end+hole_dia+5 + self.addHorizontalDimension( + center_x + web_thick / 2+web_end-hole_dia/2, y_temp, # x1, y1 + center_x + web_thick / 2 + web_end+hole_dia/2, y_temp, # x2, y2 + f"{hole_dia} mm", # Dimension label + pen # Use the pen you already have (black or any color) + ) + x_dim = -20 + + # Starting Y + if stiff_len==0: + y_current=flange_thick+web_end + else: + y_current = flangeend + self.addVerticalDimension( + x_dim, y_current-web_end, # x1, y1 + x_dim, y_current, # x2, y2 + f"{flangeend} mm", # Dimension label + pen # Use your dimension pen (black or any color) + ) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = self.arrowsize + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(self.fontsize) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = self.arrowsize + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(self.fontsize) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/Beam2ColEnddetailing.py b/src/osdag/gui/Beam2ColEnddetailing.py new file mode 100644 index 000000000..c08a4ed4d --- /dev/null +++ b/src/osdag/gui/Beam2ColEnddetailing.py @@ -0,0 +1,1154 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class BeamtoColDetailing(QMainWindow): + def __init__(self, connection_obj,main, rows=3, cols=2): + super().__init__() + self.connection = connection_obj + data=main.output_values(main,True) + self.web_thick=main.beam_tw + self.endplatetype=main.endplate_type + self.flange_thick=main.beam_tf + self.middle_bolts=main.bolt_row_web + self.stiffener_length = main.stiffener_length + self.stiffener_thickness=main.stiffener_thickness + self.rows_inside_D_max = main.rows_inside_D_max + self.rows_outside_D_max = main.rows_outside_D_max + self.detail_dict = { + entry[1]: entry[3] + for entry in data + } + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + print(f'End Plate Type : {self.endplatetype}') + print(f'middle bolts : {self.middle_bolts}') + print(f'stiffener length : {self.stiffener_length}') + + self.setGeometry(100, 100, 1200, 900) + print(f'web thickness : {self.web_thick}, flange thickness : {self.flange_thick} ') + # Step 1: Create a central widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # Step 2: Create main layout + main_layout = QHBoxLayout() + central_widget.setLayout(main_layout) + + # Step 3: Left panel for selected labels only + left_panel = QWidget() + left_layout = QVBoxLayout() + left_panel.setLayout(left_layout) + + # Only display selected keys + keys_to_display = [ + 'No. of Rows', + 'No. of Columns', + 'Pitch Distance (mm)', + 'Gauge Distance (mm)', + 'Cross-centre Gauge (mm)', # optional: if applicable + 'End Distance (mm)', + 'Edge Distance (mm)', + 'Height (mm)', + 'Width (mm)', + 'Diameter (mm)', + ] + + # Add labels + for key in keys_to_display: + if key in self.detail_dict: + value = self.detail_dict[key] + label = QLabel(f"{key}: {value}") + left_layout.addWidget(label) + self.edge_label = QLabel("Adjusted Edge Distance: computing...") + left_layout.addWidget(self.edge_label) + # Step 4: Graphics view and scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Background and test shape (optional) + self.scene.setBackgroundBrush(Qt.white) + + # Step 5: Add to main layout + main_layout.addWidget(left_panel, stretch=1) + main_layout.addWidget(self.view, stretch=3) + + # Step 6: Call parameter extraction and drawing + self.get_parameters() + self.view.scale(2.5, 2.5) + def get_parameters(self): + print('setting parameters') + self.rows=self.detail_dict['No. of Rows'] + self.cols=self.detail_dict['No. of Columns'] + print(f'rows : {self.rows} , cols : {self.cols}') + self.pitch=self.detail_dict['Pitch Distance (mm)'] + self.CrossGauge=self.detail_dict['Cross-centre Gauge (mm)'] + value = self.detail_dict['Gauge Distance (mm)'] + self.Gauge = float(value) if str(value).isdigit() else self.CrossGauge + self.End=self.detail_dict['End Distance (mm)'] + self.Edge=self.detail_dict['Edge Distance (mm)'] + self.height=self.detail_dict['Height (mm)'] + self.width=self.detail_dict['Width (mm)'] + self.hole_diameter=self.detail_dict['Diameter (mm)'] + if self.endplatetype.startswith('Flushed'): + self.createDrawingFlushedReversible() + elif self.endplatetype.startswith('Extended One'): + self.createDrawingExtendedOneWay() + else: + self.createDrawingExtendedTwoWay() + + + + #drawing setup for flushed reversible + + def createDrawingFlushedReversible(self): + from PyQt5.QtCore import Qt + from PyQt5.QtGui import QPen, QColor,QBrush + + # Inputs + webthickness = self.web_thick + flangethickness = self.flange_thick + plate_height = self.height + plate_width = self.width + rows = self.rows + cols = self.cols + pitch = self.pitch + crossgauge = float(self.CrossGauge) + end = self.End + edge = float(self.Edge) + holedia = self.hole_diameter + gauge = float(self.Gauge) + print(f'rows: {rows} , cols : {cols}') + h_gap = 12.5 + v_gap = 12.5 + outline_pen = QPen(Qt.blue, 2) + black_pen = QPen(QColor("black"), 2) + bolt_pen = QPen(Qt.blue, 2) + bolt_brush = QBrush(QColor("gold")) + radius = holedia / 2 + total_span = 2 * edge + crossgauge + extra_per_side = (cols - 2) // 2 + for _ in range(extra_per_side): + total_span += 2 * gauge + if total_span<= plate_width: + # --- Adjust edge to center the bolt group --- + edge += (plate_width - total_span) / 2 + # Scene setup + self.adjusted_edge=edge + if hasattr(self, 'edge_label'): + self.edge_label.setText(f"Adjusted Edge Distance: {self.adjusted_edge:.2f} mm") + self.scene.setSceneRect(-40, -60, plate_width + 80, plate_height + 120) + + # --- Draw plate rectangle (outer boundary) --- + self.scene.addRect(0, 0, plate_width, plate_height, black_pen) + + # --- Web Coordinates --- + web_x1 = (plate_width - webthickness) / 2 + web_x2 = web_x1 + webthickness + flange_top_y = v_gap + flange_bottom_y = plate_height - v_gap + + # Flange bottom/top edges + flange_bottom_edge_y_top = flange_top_y + flangethickness + flange_bottom_edge_y_bottom = flange_bottom_y - flangethickness + + web_y1 = flange_bottom_edge_y_top + web_y2 = flange_bottom_edge_y_bottom + outline_pen = QPen(QColor("orange")) + outline_pen.setWidth(2) + # --- Web vertical lines --- + self.scene.addLine(web_x1, web_y1, web_x1, web_y2, outline_pen) + self.scene.addLine(web_x2, web_y1, web_x2, web_y2, outline_pen) + + # --- Top Flange --- + self.scene.addLine(h_gap, flange_top_y, plate_width - h_gap, flange_top_y, outline_pen) + self.scene.addLine(h_gap, flange_bottom_edge_y_top, web_x1, flange_bottom_edge_y_top, outline_pen) + self.scene.addLine(web_x2, flange_bottom_edge_y_top, plate_width - h_gap, flange_bottom_edge_y_top, outline_pen) + self.scene.addLine(h_gap, flange_top_y, h_gap, flange_bottom_edge_y_top, outline_pen) + self.scene.addLine(plate_width - h_gap, flange_top_y, plate_width - h_gap, flange_bottom_edge_y_top, outline_pen) + + # --- Bottom Flange --- + self.scene.addLine(h_gap, flange_bottom_y, plate_width - h_gap, flange_bottom_y, outline_pen) + self.scene.addLine(h_gap, flange_bottom_edge_y_bottom, web_x1, flange_bottom_edge_y_bottom, outline_pen) + self.scene.addLine(web_x2, flange_bottom_edge_y_bottom, plate_width - h_gap, flange_bottom_edge_y_bottom, outline_pen) + self.scene.addLine(h_gap, flange_bottom_edge_y_bottom, h_gap, flange_bottom_y, outline_pen) + self.scene.addLine(plate_width - h_gap, flange_bottom_edge_y_bottom, plate_width - h_gap, flange_bottom_y, outline_pen) + + # --- Calculate total bolt span --- + # print(rows, cols) + rowstop = int(rows / 2) + outline_pen=QPen(QColor("blue")) + + + print('Total Span:', total_span) + + print('Adjusted Edge:', edge) + + # --- Draw top half bolt rows --- + y_start = 12.5 + flangethickness +end # inside top flange + + for row in range(rowstop): + y = y_start + row * pitch + x = edge # Start from adjusted edge + + for col in range(cols): + # Draw bolt at (x, y) + # print(f'row : {row} , col : {col} , x : {x} y : {y}') + + self.scene.addEllipse(x - radius, y - radius, holedia, holedia, bolt_pen) + + # Advance x for next column + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + # --- Draw bottom half bolt rows --- + y_start_bottom = plate_height - (12.5 + flangethickness + end) + + for row in range(rowstop): + y = y_start_bottom - row * pitch + x = edge # Reset x for each row + + for col in range(cols): + self.scene.addEllipse(x - radius, y - radius, holedia, holedia, bolt_pen) + + # Advance x + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + self.addDimensionsFlushedReversible(edge,gauge,crossgauge,cols) + #self.addInternalGapsFlushedReversible() + + def addInternalGapsFlushedReversible(self, margin=12.5): + from PyQt5.QtGui import QPen, QFont, QBrush + from PyQt5.QtCore import Qt, QPointF + from PyQt5.QtGui import QPolygonF + + pen = QPen(Qt.black, 1) + pen.setStyle(Qt.SolidLine) + + label_text = f"{margin:.1f} mm" + font = QFont() + font.setPointSize(7) # Increased font size + + pw = self.width + ph = self.height + + # Internal gap lines and their label offsets (dx, dy) + gap_lines = [ + # Top left + ((0, margin, margin, margin), (margin + 4, margin - 10)), # horizontal + ((margin, 0, margin, margin), (margin + 4, 2)), # vertical + + # Top right + ((pw - margin, margin, pw, margin), (pw - margin - 30, margin - 10)), + ((pw - margin, 0, pw - margin, margin), (pw - margin - 25, 2)), + + # Bottom left + ((0, ph - margin, margin, ph - margin), (margin + 4, ph - margin - 15)), + ((margin, ph - margin, margin, ph), (margin + 4, ph - margin + 2)), + + # Bottom right + ((pw - margin, ph - margin, pw, ph - margin), (pw - margin - 30, ph - margin - 15)), + ((pw - margin, ph - margin, pw - margin, ph), (pw - margin - 25, ph - margin + 2)), + ] + + for (x1, y1, x2, y2), (tx, ty) in gap_lines: + self.scene.addLine(x1, y1, x2, y2, pen) + + # Add label with clearer offset + text_item = self.scene.addText(label_text) + text_item.setFont(font) + text_item.setPos(tx, ty) + + def addDimensionsFlushedReversible(self, edge, gauge, cross_gauge, cols, y_offset=20): + """ + Draws clean, symmetric horizontal dimensions for even column layout: + [edge] + N*gauge + cross_gauge + N*gauge + [edge] + Uses self.addHorizontalDimension(). + """ + + from PyQt5.QtGui import QPen + from PyQt5.QtCore import Qt + + if cols % 2 != 0 or cols < 2: + raise ValueError("Number of columns must be even and >= 2") + + pen = QPen(Qt.black, 1) + pen.setStyle(Qt.DashLine) + y = -y_offset + + x = 0 + segments = [] + + # --- Left edge distance --- + x1 = x + x2 = x + edge + segments.append(("edge", x1, x2)) + x = x2 + + # --- Left-side gauge segments --- + for _ in range((cols - 2) // 2): + x1 = x + x2 = x + gauge + segments.append(("gauge", x1, x2)) + x = x2 + + # --- Cross gauge --- + x1 = x + x2 = x + cross_gauge + segments.append(("cross gauge", x1, x2)) + x = x2 + + # --- Right-side gauge segments --- + for _ in range((cols - 2) // 2): + x1 = x + x2 = x + gauge + segments.append(("gauge", x1, x2)) + x = x2 + + # --- Right edge distance --- + x1 = x + x2 = x + edge + segments.append(("edge", x1, x2)) + + pen = QPen(Qt.black, 0.5) + font = QFont() + font.setPointSize(4) + + # --- Draw all segments using your dimension method --- + for label, x1, x2 in segments: + self.addHorizontalDimension(x1, y, x2, y, f"{x2 - x1:.1f}", pen, font) + plate_width = self.width + y_plate = self.height + 20 # just below the plate + + self.addHorizontalDimension(0, y_plate, plate_width, y_plate, f"{plate_width:.1f} mm", pen, font) + # --- Add vertical dimensions on left side for top half --- + x_vdim = -30 # left of plate + y_base = 12.5 + + # 1. Flange thickness + y1 = y_base + y2 = y1 + self.flange_thick + self.addVerticalDimension(x_vdim, y1, x_vdim, y2, f"{self.flange_thick:.1f}", pen, font) + + # 2. End distance + y1 = y2 + y2 = y1 + self.End + self.addVerticalDimension(x_vdim, y1, x_vdim, y2, f"{self.End:.1f}", pen, font) + + # 3. Pitch segments (top rows) + for i in range(self.rows // 2 - 1): + y1 = y2 + y2 = y1 + self.pitch + self.addVerticalDimension(x_vdim, y1, x_vdim, y2, f"{self.pitch:.1f}", pen, font) + + # --- Add vertical dimensions on left side for bottom half --- + y_base = self.height - 12.5 + + # 1. Flange thickness + y1 = y_base + y2 = y1 - self.flange_thick + self.addVerticalDimension(x_vdim, y2, x_vdim, y1, f"{self.flange_thick:.1f}", pen, font) + + # 2. End distance + y1 = y2 + y2 = y1 - self.End + self.addVerticalDimension(x_vdim, y2, x_vdim, y1, f"{self.End:.1f}", pen, font) + + # 3. Pitch segments (bottom rows) + for i in range(self.rows // 2 - 1): + y1 = y2 + y2 = y1 - self.pitch + self.addVerticalDimension(x_vdim, y2, x_vdim, y1, f"{self.pitch:.1f}", pen, font) + x_total_height = self.width + 20 # to the right of the plate + y_top = 0 + y_bottom = self.height + + self.addVerticalDimension(x_total_height, y_top, x_total_height, y_bottom, f"{self.height:.1f} mm", pen, font) + + + #extended one way drawing setup + + def createDrawingExtendedOneWay(self): + from PyQt5.QtCore import Qt + from PyQt5.QtGui import QPen, QColor, QBrush + + # === Input Parameters === + plate_height = self.height + plate_width = self.width + web_thickness = self.web_thick + flange_thickness = self.flange_thick + stiffener_height = self.stiffener_length + stiffener_thickness = self.stiffener_thickness + pitch = self.pitch + end = self.End + midbolts=self.middle_bolts + rowsabovestiff=0 + crossgauge=self.CrossGauge + edge=self.Edge + gauge=self.Gauge + cols=self.cols + rows=self.rows + # Margins + h_gap = 12.5 + v_gap = 12.5 + holedia=self.hole_diameter + radius=holedia/2 + # === Pens and Brushes === + outline_pen = QPen(QColor("orange")) + red_pen = QPen(QColor("red"), 2) + red_brush = QBrush(QColor("red")) + black_pen = QPen(QColor("black"), 2) + + # === Setup Scene === + self.scene.setSceneRect(-40, -60, plate_width + 80, plate_height + 120) + self.scene.clear() + self.scene.setBackgroundBrush(Qt.white) + + # === Draw Plate Boundary === + self.scene.addRect(0, 0, plate_width, plate_height, black_pen) + + # === Determine Effective Stiffener Height === + if end + pitch + end < stiffener_height: + effective_stiffener_height = end + pitch + end + rowsabovestiff=2 + else: + effective_stiffener_height = 2 * end + rowsabovestiff=1 + self.stiff_len=effective_stiffener_height + stiffener_x = (plate_width - web_thickness) / 2 + blue_brush = QBrush(QColor("blue")) + + # === Draw Top Stiffener === + self.scene.addRect( + stiffener_x, + 0, + web_thickness, + effective_stiffener_height, + black_pen, + blue_brush + ) + self.scene.addRect( + stiffener_x - stiffener_thickness/2, + 0, + stiffener_thickness/2, + effective_stiffener_height, + black_pen, + red_brush + ) + + # Draw right stiffener + self.scene.addRect( + stiffener_x + web_thickness, + 0, + stiffener_thickness/2, + effective_stiffener_height, + black_pen, + red_brush + ) + # === Web and Flange Geometry === + top_flange_y = effective_stiffener_height + top_flange_bottom_y = top_flange_y + flange_thickness + bottom_flange_y = plate_height - v_gap + bottom_flange_top_y = bottom_flange_y - flange_thickness + + web_x1 = (plate_width - web_thickness) / 2 + web_x2 = web_x1 + web_thickness + web_y1 = top_flange_bottom_y + web_y2 = bottom_flange_top_y + weblen=web_y1-web_y2 + outline_pen.setWidth(2) + # === Draw Web === + outline_pen.setWidth(2) + self.scene.addLine(web_x1, web_y1, web_x1, web_y2, outline_pen) + self.scene.addLine(web_x2, web_y1, web_x2, web_y2, outline_pen) + + # === Draw Top Flange (5 lines) === + self.scene.addLine(h_gap, top_flange_y, plate_width - h_gap, top_flange_y, outline_pen) + self.scene.addLine(h_gap, top_flange_y, h_gap, top_flange_bottom_y, outline_pen) + self.scene.addLine(plate_width - h_gap, top_flange_y, plate_width - h_gap, top_flange_bottom_y, outline_pen) + self.scene.addLine(h_gap, top_flange_bottom_y, web_x1, top_flange_bottom_y, outline_pen) + self.scene.addLine(web_x2, top_flange_bottom_y, plate_width - h_gap, top_flange_bottom_y, outline_pen) + + # === Draw Bottom Flange (5 lines) === + self.scene.addLine(h_gap, bottom_flange_y, plate_width - h_gap, bottom_flange_y, outline_pen) + self.scene.addLine(h_gap, bottom_flange_top_y, h_gap, bottom_flange_y, outline_pen) + self.scene.addLine(plate_width - h_gap, bottom_flange_top_y, plate_width - h_gap, bottom_flange_y, outline_pen) + self.scene.addLine(h_gap, bottom_flange_top_y, web_x1, bottom_flange_top_y, outline_pen) + self.scene.addLine(web_x2, bottom_flange_top_y, plate_width - h_gap, bottom_flange_top_y, outline_pen) + total_span = 2 * edge + crossgauge + extra_per_side = (cols - 2) // 2 + for _ in range(extra_per_side): + total_span += 2 * gauge + if total_span<= plate_width: + # --- Adjust edge to center the bolt group --- + edge += (plate_width - total_span) / 2 + + y_bottom_bolt = plate_height - 12.5 - end -flange_thickness # From image: 12.5 mm gap, then e' up + blue_pen = QPen(Qt.blue) + outline_pen=blue_pen + x = edge # start x from edge + + + for col in range(cols): + self.scene.addEllipse(x - radius, y_bottom_bolt - radius, holedia, holedia, blue_pen) + # Advance x for next column + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + #draw middle bolt + if midbolts==1: + print('drawing middle bolt') + y_mid_bolt = plate_height - 12.5 - flange_thickness - abs(weblen / 2) + x = edge # Start x from adjusted edge + for col in range(cols): + print(f'x : {x} ,y : {y_mid_bolt} , col : {col}') + self.scene.addEllipse(x - radius, y_mid_bolt - radius, holedia, holedia, red_pen, red_brush) + # Advance x for next column + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + y_top_bolt = end # distance from top of plate + + x = edge # Start x from adjusted edge + for col in range(cols): + self.scene.addEllipse(x - radius, y_top_bolt - radius, holedia, holedia, blue_pen) + # Advance x for next column + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + if rowsabovestiff == 2 : + y_top_bolt = end + pitch + x = edge # Start x from adjusted edge + for col in range(cols): + self.scene.addEllipse(x - radius, y_top_bolt - radius, holedia, holedia, blue_pen) + # Advance x for next column + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + remainingrows = rows - 1 - midbolts -rowsabovestiff + self.remainingrows=remainingrows + start_y = effective_stiffener_height + flange_thickness + end # starting y position just below flange + self.rowsabovestiff=rowsabovestiff + for row in range(remainingrows): + y = start_y + row * pitch + x = edge # reset x for each row + + for col in range(cols): + self.scene.addEllipse(x - radius, y - radius, holedia, holedia, blue_pen) + # Advance x for next column + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + #self.addInternalGapsExtendedOneWay() + self.addDimensionsExtendedOneWay(edge,self.Gauge,self.CrossGauge,self.cols) + def addDimensionsExtendedOneWay(self, edge, gauge, cross_gauge, cols, y_offset=20): + from PyQt5.QtGui import QPen, QFont + from PyQt5.QtCore import Qt + + pen = QPen(Qt.black, 0.5) + font = QFont() + font.setPointSize(4) + + # === Draw vertical dimension for stiff_len from top === + x_dim_line = -15 # Position left of the plate + y1 = 0 + y2 = self.stiff_len + + + + self.addVerticalDimension(x_dim_line, y1, x_dim_line, y2, f"{self.stiff_len:.1f} mm", pen, font) + # === Draw stacked vertical dimensions on right === + x_right = self.width + 20 # Position right of the plate + current_y = 0 # Start from top + + # First end distance + y_next = current_y + self.End + self.addVerticalDimension(x_right, current_y, x_right, y_next, f"{self.End:.1f} mm", pen, font) + current_y = y_next + + # If more than 1 row above stiffener, add pitch + if self.rowsabovestiff > 1: + y_next = current_y + self.pitch + self.addVerticalDimension(x_right, current_y, x_right, y_next, f"{self.pitch:.1f} mm", pen, font) + current_y = y_next + + # Add second end distance + y_next = current_y + self.End + self.addVerticalDimension(x_right, current_y, x_right, y_next, f"{self.End:.1f} mm", pen, font) + # === Vertical Dimensions for Bolt Rows Below Stiffener === + y_start = y_next + self.flange_thick # Below stiffener flange + current_y = y_start + + if self.remainingrows >= 1: + # First bolt row: end distance + y_next = current_y + self.End + self.addVerticalDimension(x_right, current_y, x_right, y_next, f"{self.End:.1f} mm", pen, font) + current_y = y_next + + # Remaining rows: pitch + for _ in range(self.remainingrows - 1): + y_next = current_y + self.pitch + self.addVerticalDimension(x_right, current_y, x_right, y_next, f"{self.pitch:.1f} mm", pen, font) + current_y = y_next + + # === From bottom flange up to last bolt row === + y_bottom = self.height - 12.5 - self.flange_thick + y_top = y_bottom - self.End + self.addVerticalDimension(x_right, y_top, x_right, y_bottom, f"{self.End:.1f} mm", pen, font) + from PyQt5.QtGui import QPen + from PyQt5.QtCore import Qt + + if cols % 2 != 0 or cols < 2: + raise ValueError("Number of columns must be even and >= 2") + + pen = QPen(Qt.darkGreen, 1) + pen.setStyle(Qt.DashLine) + y = -y_offset + + x = 0 + segments = [] + + # --- Left edge distance --- + x1 = x + x2 = x + edge + segments.append(("edge", x1, x2)) + x = x2 + + # --- Left-side gauge segments --- + for _ in range((cols - 2) // 2): + x1 = x + x2 = x + gauge + segments.append(("gauge", x1, x2)) + x = x2 + + # --- Cross gauge --- + x1 = x + x2 = x + cross_gauge + segments.append(("cross gauge", x1, x2)) + x = x2 + + # --- Right-side gauge segments --- + for _ in range((cols - 2) // 2): + x1 = x + x2 = x + gauge + segments.append(("gauge", x1, x2)) + x = x2 + + # --- Right edge distance --- + x1 = x + x2 = x + edge + segments.append(("edge", x1, x2)) + + # --- Draw all segments using your dimension method --- + for label, x1, x2 in segments: + self.addHorizontalDimension(x1, y, x2, y, f"{x2 - x1:.1f}", pen, font) + plate_width = self.width + y_plate = self.height + 20 # just below the plate + + self.addHorizontalDimension(0, y_plate, plate_width, y_plate, f"{plate_width:.1f} mm", pen, font) + + def addInternalGapsExtendedOneWay(self, margin=12.5): + from PyQt5.QtGui import QPen, QFont + from PyQt5.QtCore import Qt + + pen = QPen(Qt.black, 1) + pen.setStyle(Qt.SolidLine) + + label_text = f"{margin:.1f} mm" + font = QFont() + font.setPointSize(7) + + pw = self.width + ph = self.height + stiff_y = self.stiff_len # Bottom of stiffener + + # Internal gap lines and their label offsets + gap_lines = [ + # Top left (only horizontal) + ((0, stiff_y, margin, stiff_y), (margin + 4, stiff_y - 10)), + + # Top right (only horizontal) + ((pw - margin, stiff_y, pw, stiff_y), (pw - margin - 30, stiff_y - 10)), + + # Bottom left + ((0, ph - margin, margin, ph - margin), (margin + 4, ph - margin - 15)), + ((margin, ph - margin, margin, ph), (margin + 4, ph - margin + 2)), + + # Bottom right + ((pw - margin, ph - margin, pw, ph - margin), (pw - margin - 30, ph - margin - 15)), + ((pw - margin, ph - margin, pw - margin, ph), (pw - margin - 25, ph - margin + 2)), + ] + + for (x1, y1, x2, y2), (tx, ty) in gap_lines: + self.scene.addLine(x1, y1, x2, y2, pen) + + text_item = self.scene.addText(label_text) + text_item.setFont(font) + text_item.setPos(tx, ty) + + def createDrawingExtendedTwoWay(self): + from PyQt5.QtCore import Qt + from PyQt5.QtGui import QPen, QColor, QBrush + + # === Input Parameters === + plate_height = self.height + plate_width = self.width + web_thickness = self.web_thick + flange_thickness = self.flange_thick + stiffener_height = self.stiffener_length + stiffener_thickness = self.stiffener_thickness + pitch = self.pitch + end = self.End + gauge= self.Gauge + crossgauge=self.CrossGauge + cols=self.cols + rows=self.rows + holedia=self.hole_diameter + radius=holedia/2 + edge=self.Edge + # Horizontal margin only + h_gap = 12.5 + + # === Pens and Brushes === + outline_pen = QPen(QColor("orange")) + red_pen = QPen(QColor("red"), 2) + red_brush = QBrush(QColor("red")) + black_pen = QPen(QColor("black"), 2) + + # === Setup Scene === + self.scene.setSceneRect(-40, -60, plate_width + 80, plate_height + 120) + self.scene.clear() + self.scene.setBackgroundBrush(Qt.white) + + # === Draw Plate Boundary === + self.scene.addRect(0, 0, plate_width, plate_height, black_pen) + + # === Determine Effective Stiffener Height (Top and Bottom) === + if end + pitch + end < stiffener_height: + effective_stiffener_height = end + pitch + end + rowsabovestiff = 2 + else: + effective_stiffener_height = 2 * end + rowsabovestiff = 1 + self.stiff_len = effective_stiffener_height + self.rowsabovestiff = rowsabovestiff + blue_brush = QBrush(QColor("blue")) + blue_pen = QPen(Qt.blue) + + # === Draw Top Stiffener === + stiffener_x = (plate_width - web_thickness) / 2 + self.scene.addRect( + stiffener_x, + 0, + web_thickness, + effective_stiffener_height, + black_pen, + blue_brush + ) + self.scene.addRect( + stiffener_x - stiffener_thickness/2, + 0, + stiffener_thickness/2, + effective_stiffener_height, + black_pen, + red_brush + ) + + # Draw right stiffener + self.scene.addRect( + stiffener_x + web_thickness, + 0, + stiffener_thickness/2, + effective_stiffener_height, + black_pen, + red_brush + ) + # === Draw Bottom Stiffener === + stiffener_x = (plate_width - web_thickness) / 2 + stiffener_y = plate_height - effective_stiffener_height + + # Center stiffener + self.scene.addRect( + stiffener_x, + stiffener_y, + web_thickness, + effective_stiffener_height, + black_pen, + blue_brush + ) + + # Left stiffener + self.scene.addRect( + stiffener_x - stiffener_thickness/2, + stiffener_y, + stiffener_thickness/2, + effective_stiffener_height, + black_pen, + red_brush + ) + + # Right stiffener + self.scene.addRect( + stiffener_x + web_thickness, + stiffener_y, + stiffener_thickness/2, + effective_stiffener_height, + black_pen, + red_brush + ) + # === Calculate flange and web geometry === + top_flange_y = effective_stiffener_height + top_flange_bottom_y = top_flange_y + flange_thickness + + bottom_flange_bottom_y = plate_height - effective_stiffener_height + bottom_flange_top_y = bottom_flange_bottom_y - flange_thickness + + web_x1 = (plate_width - web_thickness) / 2 + web_x2 = web_x1 + web_thickness + web_y1 = top_flange_bottom_y + web_y2 = bottom_flange_top_y + outline_pen.setWidth(2) + # === Draw Top Flange (5-line detail) === + self.scene.addLine(h_gap, top_flange_y, plate_width - h_gap, top_flange_y, outline_pen) + self.scene.addLine(h_gap, top_flange_y, h_gap, top_flange_bottom_y, outline_pen) + self.scene.addLine(plate_width - h_gap, top_flange_y, plate_width - h_gap, top_flange_bottom_y, outline_pen) + self.scene.addLine(h_gap, top_flange_bottom_y, web_x1, top_flange_bottom_y, outline_pen) + self.scene.addLine(web_x2, top_flange_bottom_y, plate_width - h_gap, top_flange_bottom_y, outline_pen) + + # === Draw Bottom Flange (5-line detail) === + self.scene.addLine(h_gap, bottom_flange_bottom_y, plate_width - h_gap, bottom_flange_bottom_y, outline_pen) + self.scene.addLine(h_gap, bottom_flange_top_y, h_gap, bottom_flange_bottom_y, outline_pen) + self.scene.addLine(plate_width - h_gap, bottom_flange_top_y, plate_width - h_gap, bottom_flange_bottom_y, outline_pen) + self.scene.addLine(h_gap, bottom_flange_top_y, web_x1, bottom_flange_top_y, outline_pen) + self.scene.addLine(web_x2, bottom_flange_top_y, plate_width - h_gap, bottom_flange_top_y, outline_pen) + + # === Draw Web (clean, between flanges only) === + self.scene.addLine(web_x1, web_y1, web_x1, web_y2, outline_pen) + self.scene.addLine(web_x2, web_y1, web_x2, web_y2, outline_pen) + total_span = 2 * edge + crossgauge + extra_per_side = (cols - 2) // 2 + for _ in range(extra_per_side): + total_span += 2 * gauge + if total_span<= plate_width: + # --- Adjust edge to center the bolt group --- + edge += (plate_width - total_span) / 2 + x = edge + y_top_bolt = self.End + outline_pen=blue_pen + for col in range(cols): + self.scene.addEllipse(x - radius, y_top_bolt - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + +# Optional second row above stiffener + if self.rowsabovestiff == 2: + x = edge + y_top_bolt_2 = self.End + pitch + for col in range(cols): + self.scene.addEllipse(x - radius, y_top_bolt_2 - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + +# === Draw Bolt Rows from Bottom === + x = edge + y_bottom_bolt = self.height - self.End + + for col in range(cols): + self.scene.addEllipse(x - radius, y_bottom_bolt - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + + # Optional second row below stiffener + if self.rowsabovestiff == 2: + x = edge + y_bottom_bolt_2 = self.height - self.End - pitch + for col in range(cols): + self.scene.addEllipse(x - radius, y_bottom_bolt_2 - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + remainingrows=rows-2*self.rowsabovestiff-self.middle_bolts + if self.middle_bolts==1: + x = edge + y_mid_bolt = self.height / 2 + + for col in range(cols): + self.scene.addEllipse(x - radius, y_mid_bolt - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + # === Split remaining rows symmetrically === + top_rows = (remainingrows + 1) // 2 + bottom_rows = remainingrows // 2 + self.top_rows=top_rows + self.bottom_rows=bottom_rows + # Determine starting y for top and bottom + if self.rowsabovestiff == 2: + last_top_y = self.End + pitch+flange_thickness + else: + last_top_y = self.End+flange_thickness + + if self.rowsabovestiff == 2: + last_bottom_y = self.height - self.End - pitch-flange_thickness + else: + last_bottom_y = self.height - self.End-flange_thickness + + # === Draw top part of remaining rows === + for i in range(top_rows): + y = last_top_y + (i + 1) * pitch # start one pitch below the last top bolt + x = edge + for col in range(cols): + self.scene.addEllipse(x - radius, y - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + + # === Draw bottom part of remaining rows === + for i in range(bottom_rows): + y = last_bottom_y - (i + 1) * pitch # start one pitch above the last bottom bolt + x = edge + for col in range(cols): + self.scene.addEllipse(x - radius, y - radius, holedia, holedia, blue_pen) + if col == 0 or col == 2: + x += gauge + elif col == 1: + x += crossgauge + #self.addInternalGapsExtendedTwoWay(effective_stiffener_height) + self.addDimensionsExtendedTwoWay(edge,gauge,crossgauge,cols,effective_stiffener_height) + def addDimensionsExtendedTwoWay(self, edge, gauge, cross_gauge, cols, finalstifflen, y_offset=20): + from PyQt5.QtGui import QPen, QFont + from PyQt5.QtCore import Qt + + pen = QPen(Qt.black, 0.5) + font = QFont() + font.setPointSize(4) + + x_left = -20 # Left of plate + + # === TOP DIMENSIONS === + current_y = 0 + + # 1. First edge distance + next_y = current_y + self.End + self.addVerticalDimension(x_left, current_y, x_left, next_y, f"{self.End:.1f} mm", pen, font) + current_y = next_y + + # 2. Pitch if rowsabovestiff == 2 + if self.rowsabovestiff == 2: + next_y = current_y + self.pitch + self.addVerticalDimension(x_left, current_y, x_left, next_y, f"{self.pitch:.1f} mm", pen, font) + current_y = next_y + + # 3. Second edge distance (above flange) + next_y = current_y + self.End + self.addVerticalDimension(x_left, current_y, x_left, next_y, f"{self.End:.1f} mm", pen, font) + current_y = next_y + + # 4. Flange thickness + next_y = current_y + self.flange_thick + self.addVerticalDimension(x_left, current_y, x_left, next_y, f"{self.flange_thick:.1f} mm", pen, font) + current_y = next_y + next_y = current_y + self.End + self.addVerticalDimension(x_left, current_y, x_left, next_y, f"{self.End:.1f} mm", pen, font) + current_y = next_y + # 5. Top bolt pitches + for i in range(self.top_rows-1): + next_y = current_y + self.pitch + self.addVerticalDimension(x_left, current_y, x_left, next_y, f"{self.pitch:.1f} mm", pen, font) + current_y = next_y + + # === Total plate height dimension (right side) === + x_right = self.width + 20 + self.addVerticalDimension(x_right, 0, x_right, self.height, f"{self.height:.1f} mm", pen, font) + + # === Horizontal EDGE and GAUGE dimensions === + x = 0 + y_horizontal_dim = self.height-self.End # Use top bolt row as horizontal dimension reference + + segments = [] + + # Left edge + x1 = x + x2 = x + edge + segments.append((x1, x2)) + x = x2 + + # Left gauges + for _ in range((cols - 2) // 2): + x1 = x + x2 = x + gauge + segments.append((x1, x2)) + x = x2 + + # Cross gauge + x1 = x + x2 = x + cross_gauge + segments.append((x1, x2)) + x = x2 + + # Right gauges + for _ in range((cols - 2) // 2): + x1 = x + x2 = x + gauge + segments.append((x1, x2)) + x = x2 + + # Right edge + x1 = x + x2 = x + edge + segments.append((x1, x2)) + pen = QPen(Qt.black, 0.5) + font = QFont() + font.setPointSize(3) + + for x1, x2 in segments: + self.addHorizontalDimension(x1, self.height+10, x2, self.height+10, f"{x2 - x1:.1f} mm", pen, font) + + # === Full Plate Width === + # y_plate = self.height + 20 + # self.addHorizontalDimension(0, y_plate+20, self.width, y_plate+20, f"{self.width:.1f} mm", pen) + + def addInternalGapsExtendedTwoWay(self, finalstifflen, margin=12.5): + from PyQt5.QtGui import QPen, QFont + from PyQt5.QtCore import Qt + + pen = QPen(Qt.black, 1) + pen.setStyle(Qt.SolidLine) + + label_text = f"{margin:.1f} mm" + font = QFont() + font.setPointSize(7) + + pw = self.width + ph = self.height + + # Y-positions: one from top, one from bottom + y_top = finalstifflen + y_bottom = ph - finalstifflen + + # Define 4 horizontal gap lines: top-left, top-right, bottom-left, bottom-right + gap_lines = [ + # Top left + ((0, y_top, margin, y_top), (margin + 4, y_top - 10)), + # Top right + ((pw - margin, y_top, pw, y_top), (pw - margin - 30, y_top - 10)), + # Bottom left + ((0, y_bottom, margin, y_bottom), (margin + 4, y_bottom - 10)), + # Bottom right + ((pw - margin, y_bottom, pw, y_bottom), (pw - margin - 30, y_bottom - 10)), + ] + + for (x1, y1, x2, y2), (tx, ty) in gap_lines: + self.scene.addLine(x1, y1, x2, y2, pen) + + text_item = self.scene.addText(label_text) + text_item.setFont(font) + text_item.setPos(tx, ty) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen, font=None): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + if font is not None: + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen, font=None): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + if font is not None: + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/additionalfns.py b/src/osdag/gui/additionalfns.py new file mode 100644 index 000000000..002408c81 --- /dev/null +++ b/src/osdag/gui/additionalfns.py @@ -0,0 +1,9 @@ +def calculate_total_width(edge, gauge1, gauge2, cols): + width = 0 + for i in range(cols - 1): + if i % 2 == 0: + width += gauge1 + else: + width += gauge2 + total_width = width + 2 * edge + return total_width \ No newline at end of file diff --git a/src/osdag/gui/b2bcoverplateweld.py b/src/osdag/gui/b2bcoverplateweld.py new file mode 100644 index 000000000..543d8847a --- /dev/null +++ b/src/osdag/gui/b2bcoverplateweld.py @@ -0,0 +1,290 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene,QGraphicsRectItem) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont , QColor +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class B2Bcoverplateweld(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + print(main) + if main: + self.web=main[1] + web=main[1] + main=main[0] + super().__init__() + self.connection = connection_obj + data=main.output_values(main,True) + + print(type(main)) + dict1={i[0] : i[3] for i in data} + for i in dict1: + print(f'{i} : {dict1[i]}') + print("????????????????????????????DEBUG?????????????????????????????") + print(dict1) + print("????????????????????????????DEBUG?????????????????????????????") + + if web==True: + self.plate_length=main.web_plate.height + self.plate_width=main.web_plate.length + self.plate_thickness=float(dict1['Connector.Web_Plate.Thickness_List']) + self.weld_size=main.web_weld.size + self.weld_gap=main.web_plate.gap + elif web==False: + self.plate_width=main.flange_plate.length + self.plate_length=main.flange_plate.height + self.plate_thickness=float(dict1['Connector.Flange_Plate.Thickness_list']) + self.weld_size=main.flange_weld.size + self.weld_gap=main.flange_plate.gap + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + print(f""" + ----------------------------------------- + Plate Configuration Summary + ----------------------------------------- + Plate Length : {self.plate_length} mm + Plate Width : {self.plate_width} mm + Weld size : {self.weld_size} mm + Weld gap : {self.weld_gap} mm + """) + + self.setGeometry(100, 100, 800, 500) + # Step 1: Create a central widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # Step 2: Create main layout + main_layout = QHBoxLayout() + central_widget.setLayout(main_layout) + + # Step 3: Left panel for selected labels only + left_panel = QWidget() + left_layout = QVBoxLayout() + left_panel.setLayout(left_layout) + + # Only display selected keys + keys_to_display = [ + 'Plate Length', + 'Plate Width', + + ] + + # Define the corresponding values for the keys (assumes self. are already set) + values_to_display = { + 'Plate Length': self.plate_length, + 'Plate Width': self.plate_width, + + } + + + for key in keys_to_display: + if key in values_to_display: + label = QLabel(f"{key}: {values_to_display[key]}") + left_layout.addWidget(label) + # Step 4: Graphics view and scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Background and test shape (optional) + self.scene.setBackgroundBrush(Qt.white) + + # Step 5: Add to main layout + main_layout.addWidget(self.view, stretch=2) + main_layout.addWidget(left_panel, stretch=1) + + self.fontsize=10 + self.arrowsize=10 + + if self.plate_length>1200 or self.plate_width>1200: + self.fontsize=5 + self.arrowsize=5 + elif self.plate_length>600 or self.plate_width>600: + self.fontsize=10 + self.arrowsize=10 + self.createDrawing() + if self.plate_length>1200 or self.plate_width>1200: + self.view.resetTransform() + self.view.scale(0.4, 0.4) + elif self.plate_length>600 or self.plate_width>600: + self.view.resetTransform() + self.view.scale(0.75, 0.75) + + # Step 6: Call parameter extraction and drawing + + + def createDrawing(self): + try: + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + except (TypeError, ValueError): + print("Invalid plate dimensions") + return + rect = QRectF(0, 0, plate_length, plate_width) + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(Qt.black) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush(Qt.NoBrush)) + + # Add rectangle to the scene + self.scene.addItem(rect_item) + # Extract parameters + outline_pen = QPen(Qt.black) + outline_pen.setWidth(2) + + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, plate_length, plate_width)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(Qt.white)) + self.scene.addItem(rect_item) + + dimension_pen = QPen(Qt.black, 1.5) + weld_fill = QBrush(Qt.blue) + if self.web==True: + self.scene.addRect(0, (plate_width-self.plate_thickness)/2 , plate_length, self.plate_thickness, dimension_pen, weld_fill) + elif self.web==False: + self.scene.addRect((plate_length-self.plate_thickness)/2, 0 , self.plate_thickness, plate_width, dimension_pen, weld_fill) + # === Center of the base plate === + center_x = plate_length / 2 + center_y = plate_width / 2 + self.addHorizontalDimension( + 0, -30, # x1 at left edge, y above plate + self.plate_length, -30, # x2 at right edge, same y + f"{self.plate_length} mm", pen + ) + + # Vertical dimension for plate width (to the left of the plate) + self.addVerticalDimension( + self.plate_length+30, 0, # x left of plate, y1 at top + self.plate_length+30, self.plate_width, # x2 same, y2 at bottom + f"{self.plate_width} mm", pen + ) + weld_size=self.weld_size + weld_gap=self.weld_gap + red_brush = QBrush(Qt.red) + + # === Top weld outside plate === + top_weld = QGraphicsRectItem(QRectF(0, -weld_size, plate_length, weld_size)) + top_weld.setBrush(red_brush) + self.scene.addItem(top_weld) + + # === Bottom weld outside plate === + bottom_weld = QGraphicsRectItem(QRectF(0, plate_width, plate_length, weld_size)) + bottom_weld.setBrush(red_brush) + self.scene.addItem(bottom_weld) + + # === Vertical welds (left and right), split due to weld_gap === + half_gap = weld_gap / 2 + half_height = (plate_width - weld_gap) / 2 + + # Left side, top weld (outside) + left_top = QGraphicsRectItem(QRectF(-weld_size, 0, weld_size, half_height)) + left_top.setBrush(red_brush) + self.scene.addItem(left_top) + + # Left side, bottom weld (outside) + left_bottom = QGraphicsRectItem(QRectF(-weld_size, plate_width - half_height, weld_size, half_height)) + left_bottom.setBrush(red_brush) + self.scene.addItem(left_bottom) + + # Right side, top weld (outside) + right_top = QGraphicsRectItem(QRectF(plate_length, 0, weld_size, half_height)) + right_top.setBrush(red_brush) + self.scene.addItem(right_top) + + # Right side, bottom weld (outside) + right_bottom = QGraphicsRectItem(QRectF(plate_length, plate_width - half_height, weld_size, half_height)) + right_bottom.setBrush(red_brush) + self.scene.addItem(right_bottom) + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = self.arrowsize + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(self.fontsize) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = self.arrowsize + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(self.fontsize) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/b2cendplateSketch.py b/src/osdag/gui/b2cendplateSketch.py new file mode 100644 index 000000000..140623855 --- /dev/null +++ b/src/osdag/gui/b2cendplateSketch.py @@ -0,0 +1,702 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class B2BEndPlateSketch(QMainWindow): + def __init__(self, connection_obj,main, rows=3, cols=2): + super().__init__() + self.connection = connection_obj + data=main.output_values(main,True) + self.web_thick=main.beam_tw + self.endplatetype=main.endplate_type + self.flange_thick=main.beam_tf + self.middle_bolts=main.bolt_row_web + self.stiffener_length = main.stiffener_height + self.stiffener_thickness=main.stiffener_thickness + self.stiffener_width=main.stiffener_length + self.rows_inside_D_max = main.rows_inside_D_max + self.rows_outside_D_max = main.rows_outside_D_max + self.detail_dict = { + entry[1]: entry[3] + for entry in data + } + for i in self.detail_dict: + print(f' {i} : {self.detail_dict[i]}') + self.beam_width=main.beam_D + print(f'Beam Width : {main.beam_bf} , Beam Depth : {main.beam_D}') + print(self.stiffener_width,self.stiffener_length) + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + print(f'End Plate Type : {self.endplatetype}') + print(f'middle bolts : {self.middle_bolts}') + print(f'stiffener length : {self.stiffener_length}') + + self.setGeometry(100, 100, 1200, 500) + print(f'web thickness : {self.web_thick}, flange thickness : {self.flange_thick} ') + # Step 1: Create a central widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # Step 2: Create main layout + main_layout = QHBoxLayout() + central_widget.setLayout(main_layout) + + # Step 3: Left panel for selected labels only + left_panel = QWidget() + left_layout = QVBoxLayout() + left_panel.setLayout(left_layout) + + # Only display selected keys + keys_to_display = [ + + ] + + # Add labels + for key in keys_to_display: + if key in self.detail_dict: + value = self.detail_dict[key] + label = QLabel(f"{key}: {value}") + left_layout.addWidget(label) + + # Step 4: Graphics view and scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Background and test shape (optional) + self.scene.setBackgroundBrush(Qt.white) + + # Step 5: Add to main layout + main_layout.addWidget(left_panel, stretch=1) + main_layout.addWidget(self.view, stretch=3) + + # Step 6: Call parameter extraction and drawing + self.get_parameters() + def get_parameters(self): + print('setting parameters') + self.rows=self.detail_dict['No. of Rows'] + self.cols=self.detail_dict['No. of Columns'] + print(f'rows : {self.rows} , cols : {self.cols}') + self.pitch=self.detail_dict['Pitch Distance (mm)'] + self.CrossGauge=self.detail_dict['Cross-centre Gauge (mm)'] + value = self.detail_dict['Gauge Distance (mm)'] + self.Gauge = float(value) if str(value).isdigit() else self.CrossGauge + self.End=self.detail_dict['End Distance (mm)'] + self.Edge=self.detail_dict['Edge Distance (mm)'] + self.height=self.detail_dict['Height (mm)'] + self.width=self.detail_dict['Width (mm)'] + self.hole_diameter=self.detail_dict['Diameter (mm)'] + self.plate_thickness=self.detail_dict['Thickness (mm)'] + if self.endplatetype.startswith('Flushed'): + self.createDrawingFlushedReversible() + elif self.endplatetype.startswith('Extended One'): + self.createDrawingExtendedOneWay() + else: + self.createDrawingExtendedTwoWay() + def createDrawingFlushedReversible(self): + from PyQt5.QtCore import Qt + from PyQt5.QtGui import QPen, QColor, QBrush,QPolygonF + from PyQt5.QtWidgets import QGraphicsRectItem,QGraphicsPolygonItem + # === Input Parameters === + plate_height = self.height + stiffener_height = self.stiffener_length + stiffener_width=self.stiffener_width + stiffener_thickness=self.stiffener_thickness + plate_thickness=self.plate_thickness + print('stiff thicknes:',stiffener_thickness , 'stiff width : ',stiffener_width) + h_gap = 12.5 + flange_thick=self.flange_thick + beam_width=self.beam_width + total_plate_width = 2 * plate_thickness + view_width,view_height=800,800 + start_x = (view_width - total_plate_width) / 2 + start_y = (view_height - plate_height) / 2 + + # Draw first plate + total_plate_width = 2 * plate_thickness + start_x = (view_width - total_plate_width) / 2 + start_y = (view_height - plate_height) / 2 + + # === Pen (blue border, no fill) === + blue_pen = QPen(QColor("blue")) + blue_pen.setWidth(2) + blackpen=QPen(QColor("black")) + # === Draw Rectangles === + self.scene.addRect(start_x, start_y, plate_thickness, plate_height, blue_pen) + dim_y = start_y + plate_height + 20 # 20 px below + self.addHorizontalDimension(start_x, dim_y, start_x + plate_thickness, dim_y, str(plate_thickness), blackpen) + self.addHorizontalDimension(start_x, dim_y, start_x -beam_width, dim_y, str(beam_width), blackpen) + self.addVerticalDimension(start_x-beam_width-20,start_y,start_x-beam_width-20,start_y+plate_height , str(plate_height),blackpen) + self.scene.addRect(start_x + plate_thickness, start_y, plate_thickness, plate_height, blue_pen, ) + red_brush = QBrush(QColor("red")) + red_pen = QPen(Qt.NoPen) # No border for stiffeners + + stiffener_width = stiffener_thickness / 2 + + beam_y = start_y + 12.5 + beam_height = plate_height - 2 *12.5 + pen = QPen(QColor("orange")) + # Left beam rectangle (left of left plate) + self.scene.addRect( + start_x - beam_width, + beam_y, + beam_width, + beam_height, + pen, + QBrush(Qt.NoBrush) + ) + + # Right beam rectangle (right of right plate) + self.scene.addRect( + start_x + 2 * plate_thickness, + beam_y, + beam_width, + beam_height, + pen, + QBrush(Qt.NoBrush) + ) + + stiffener_width=self.stiffener_width + # X coordinates + x_left_start = start_x + x_left_end = start_x-beam_width + + x_right_end = start_x+2*plate_thickness + x_right_start = x_right_end +beam_width + + # Y positions + y_top = start_y+ flange_thick + 12.5 + y_bottom = (start_y+plate_height) - 12.5 - flange_thick + + # Left-top horizontal line + self.scene.addLine(x_left_start, y_top, x_left_end, y_top, pen) + + # Left-bottom horizontal line + self.scene.addLine(x_left_start, y_bottom, x_left_end, y_bottom, pen) + + # Right-top horizontal line + self.scene.addLine(x_right_start, y_top, x_right_end, y_top, pen) + + # Right-bottom horizontal line + self.scene.addLine(x_right_start, y_bottom, x_right_end, y_bottom, pen) + self.view.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) + pen = QPen(QColor("black")) + pen.setWidth(2) + offset_len = 25 # 25mm offset for both lines + +# Coordinates for the top-left corner of the left plate + pen = QPen(Qt.black, 2) + pen2=QPen(Qt.black, 1) + brush = QBrush(Qt.NoBrush) + half_thick = stiffener_thickness / 2.0 + + self.scene.addRect( + start_x - stiffener_thickness, + start_y+12.5, + stiffener_thickness, + plate_height - 2*12.5, + red_pen, + red_brush + ) + self.scene.addRect( + start_x +2*plate_thickness, + start_y+12.5, + stiffener_thickness, + plate_height - 2*12.5, + red_pen, + red_brush + ) + + def createDrawingExtendedOneWay(self): + from PyQt5.QtCore import Qt + from PyQt5.QtGui import QPen, QColor, QBrush,QPolygonF + from PyQt5.QtWidgets import QGraphicsRectItem,QGraphicsPolygonItem + # === Input Parameters === + plate_height = self.height + stiffener_height = self.stiffener_length + stiffener_width=self.stiffener_width + stiffener_thickness=self.stiffener_thickness + plate_thickness=self.plate_thickness + print('stiff thicknes:',stiffener_thickness , 'stiff width : ',stiffener_width) + h_gap = 12.5 + flange_thick=self.flange_thick + beam_width=self.beam_width + total_plate_width = 2 * plate_thickness + view_width,view_height=800,800 + start_x = (view_width - total_plate_width) / 2 + start_y = (view_height - plate_height) / 2 + blackpen=QPen(QColor("black")) + # Draw first plate + total_plate_width = 2 * plate_thickness + start_x = (view_width - total_plate_width) / 2 + start_y = (view_height - plate_height) / 2 + + # === Pen (blue border, no fill) === + blue_pen = QPen(QColor("blue")) + blue_pen.setWidth(2) + + # === Draw Rectangles === + self.scene.addRect(start_x, start_y, plate_thickness, plate_height, blue_pen) + self.scene.addRect(start_x + plate_thickness, start_y, plate_thickness, plate_height, blue_pen, ) + red_brush = QBrush(QColor("red")) + red_pen = QPen(Qt.NoPen) # No border for stiffeners + dim_y = start_y + plate_height + 20 # 20 px below + self.addHorizontalDimension(start_x, dim_y, start_x + plate_thickness, dim_y, str(plate_thickness), blackpen) + self.addHorizontalDimension(start_x, dim_y, start_x -beam_width, dim_y, str(beam_width), blackpen) + self.addVerticalDimension(start_x-beam_width-20,start_y,start_x-beam_width-20,start_y+plate_height , str(plate_height),blackpen) + + stiffener_width = stiffener_thickness / 2 + + # Top stiffener (left of left plate) + self.scene.addRect( + start_x - stiffener_width, + start_y, + stiffener_width, + stiffener_height, + red_pen, + red_brush + ) + self.scene.addRect( + start_x - 2*stiffener_width, + start_y+stiffener_height, + 2*stiffener_width, + plate_height-stiffener_height, + red_pen, + red_brush + ) + self.scene.addRect( + start_x + 2 * plate_thickness, + start_y+stiffener_height, + 2*stiffener_width, + plate_height-stiffener_height, + red_pen, + red_brush + ) + self.scene.addRect( + start_x + 2 * plate_thickness, # Right side of right plate + start_y, + stiffener_width, + stiffener_height, + red_pen, + red_brush + ) + + beam_y = start_y + stiffener_height + beam_height = plate_height -stiffener_height-12.5 + pen = QPen(QColor("orange")) + # Left beam rectangle (left of left plate) + self.scene.addRect( + start_x - beam_width, + beam_y, + beam_width, + beam_height, + pen, + QBrush(Qt.NoBrush) + ) + + # Right beam rectangle (right of right plate) + self.scene.addRect( + start_x + 2 * plate_thickness, + beam_y, + beam_width, + beam_height, + pen, + QBrush(Qt.NoBrush) + ) + + stiffener_width=self.stiffener_width + # X coordinates + x_left_start = start_x + x_left_end = start_x-beam_width + + x_right_end = start_x+2*plate_thickness + x_right_start = x_right_end +beam_width + + # Y positions + y_top = start_y+stiffener_height + flange_thick + y_bottom = (start_y+plate_height) - flange_thick-12.5 + + # Left-top horizontal line + self.scene.addLine(x_left_start, y_top, x_left_end, y_top, pen) + + # Left-bottom horizontal line + self.scene.addLine(x_left_start, y_bottom, x_left_end, y_bottom, pen) + + # Right-top horizontal line + self.scene.addLine(x_right_start, y_top, x_right_end, y_top, pen) + + # Right-bottom horizontal line + self.scene.addLine(x_right_start, y_bottom, x_right_end, y_bottom, pen) + self.view.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) + pen = QPen(QColor("black")) + pen.setWidth(2) + offset_len = 25 # 25mm offset for both lines + +# Coordinates for the top-left corner of the left plate + pen = QPen(Qt.black, 2) + pen2=QPen(Qt.black, 1) + brush = QBrush(Qt.NoBrush) + half_thick = stiffener_thickness / 2.0 + # === TOP LEFT === + x1, y1 = start_x, start_y + x2, y2 = start_x - offset_len, start_y + x3, y3 = start_x - stiffener_width, start_y + stiffener_height - offset_len + x4, y4 = start_x - stiffener_width, start_y + stiffener_height + x5, y5 = start_x, start_y + stiffener_height + points_tl = [QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3), QPointF(x4, y4), QPointF(x5, y5)] + polygon_tl = QGraphicsPolygonItem(QPolygonF(points_tl)) + polygon_tl.setPen(pen) + polygon_tl.setBrush(brush) + self.scene.addItem(polygon_tl) + # Red cap + x6, y6 = x5, y5 - half_thick + x7, y7 = x4, y4 - half_thick + polygon_tl = QGraphicsPolygonItem(QPolygonF([QPointF(x4, y4), QPointF(x5, y5), QPointF(x6, y6), QPointF(x7, y7)])) + polygon_tl.setPen(pen) + polygon_tl.setBrush(red_brush) + self.scene.addItem(polygon_tl) + + # Red cap + + # === TOP RIGHT === + x1, y1 = start_x + 2 * plate_thickness, start_y + x2, y2 = x1 + offset_len, start_y + x3, y3 = x1 + stiffener_width, start_y + stiffener_height - offset_len + x4, y4 = x1 + stiffener_width, start_y + stiffener_height + x5, y5 = x1, start_y + stiffener_height + points_tr = [QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3), QPointF(x4, y4), QPointF(x5, y5)] + polygon_tr = QGraphicsPolygonItem(QPolygonF(points_tr)) + polygon_tr.setPen(pen) + polygon_tr.setBrush(brush) + self.scene.addItem(polygon_tr) + # Red cap + x6, y6 = x5, y5 - half_thick + x7, y7 = x4, y4 - half_thick + polygon_tl = QGraphicsPolygonItem(QPolygonF([QPointF(x4, y4), QPointF(x5, y5), QPointF(x6, y6), QPointF(x7, y7)])) + polygon_tl.setPen(pen) + polygon_tl.setBrush(red_brush) + self.scene.addItem(polygon_tl) + + # Red cap + + self.addHorizontalDimension(start_x,start_y-40,start_x-stiffener_width,start_y-40,str(stiffener_width),blackpen) + xpos=start_x +2*plate_thickness +stiffener_width+20 + self.addVerticalDimension(xpos,start_y,xpos,start_y+stiffener_height,str(stiffener_height),blackpen) + # self.addInternalGapsExtendedOneWay() + # self.addDimensionsExtendedOneWay(edge,self.Gauge,self.CrossGauge,self.cols) + + def createDrawingExtendedTwoWay(self): + from PyQt5.QtCore import Qt + from PyQt5.QtGui import QPen, QColor, QBrush,QPolygonF + from PyQt5.QtWidgets import QGraphicsRectItem,QGraphicsPolygonItem + # === Input Parameters === + plate_height = self.height + stiffener_height = self.stiffener_length + stiffener_width=self.stiffener_width + stiffener_thickness=self.stiffener_thickness + plate_thickness=self.plate_thickness + print('stiff thicknes:',stiffener_thickness , 'stiff width : ',stiffener_width) + h_gap = 12.5 + flange_thick=self.flange_thick + beam_width=self.beam_width + total_plate_width = 2 * plate_thickness + view_width,view_height=800,800 + start_x = (view_width - total_plate_width) / 2 + start_y = (view_height - plate_height) / 2 + + # Draw first plate + total_plate_width = 2 * plate_thickness + start_x = (view_width - total_plate_width) / 2 + start_y = (view_height - plate_height) / 2 + + # === Pen (blue border, no fill) === + blue_pen = QPen(QColor("blue")) + blue_pen.setWidth(2) + blackpen=QPen(QColor("black")) + # === Draw Rectangles === + self.scene.addRect(start_x, start_y, plate_thickness, plate_height, blue_pen) + self.scene.addRect(start_x + plate_thickness, start_y, plate_thickness, plate_height, blue_pen, ) + red_brush = QBrush(QColor("red")) + red_pen = QPen(Qt.NoPen) # No border for stiffeners + dim_y = start_y + plate_height + 20 # 20 px below + self.addHorizontalDimension(start_x, dim_y, start_x + plate_thickness, dim_y, str(plate_thickness), blackpen) + self.addHorizontalDimension(start_x, dim_y, start_x -beam_width, dim_y, str(beam_width), blackpen) + self.addVerticalDimension(start_x-beam_width-20,start_y,start_x-beam_width-20,start_y+plate_height , str(plate_height),blackpen) + + stiffener_width = stiffener_thickness / 2 + + # Top stiffener (left of left plate) + self.scene.addRect( + start_x - stiffener_width, + start_y, + stiffener_width, + stiffener_height, + red_pen, + red_brush + ) + self.scene.addRect( + start_x - 2*stiffener_width, + start_y+stiffener_height, + stiffener_width*2, + plate_height-2*stiffener_height, + red_pen, + red_brush + ) + + # Bottom stiffener (left of left plate) + self.scene.addRect( + start_x - stiffener_width, + start_y + plate_height - stiffener_height, + stiffener_width, + stiffener_height, + red_pen, + red_brush + ) + self.scene.addRect( + start_x + 2 * plate_thickness, # Right side of right plate + start_y, + stiffener_width, + stiffener_height, + red_pen, + red_brush + ) + self.scene.addRect( + start_x + 2 * plate_thickness, # Right side of right plate + start_y+stiffener_height, + stiffener_width*2, + plate_height-2*stiffener_height, + red_pen, + red_brush + ) + + self.scene.addRect( + start_x + 2 * plate_thickness, # Right side of right plate + start_y + plate_height - stiffener_height, + stiffener_width, + stiffener_height, + red_pen, + red_brush + ) + beam_y = start_y + stiffener_height + beam_height = plate_height - 2 * stiffener_height + pen = QPen(QColor("orange")) + # Left beam rectangle (left of left plate) + self.scene.addRect( + start_x - beam_width, + beam_y, + beam_width, + beam_height, + pen, + QBrush(Qt.NoBrush) + ) + + # Right beam rectangle (right of right plate) + self.scene.addRect( + start_x + 2 * plate_thickness, + beam_y, + beam_width, + beam_height, + pen, + QBrush(Qt.NoBrush) + ) + + stiffener_width=self.stiffener_width + # X coordinates + x_left_start = start_x + x_left_end = start_x-beam_width + + x_right_end = start_x+2*plate_thickness + x_right_start = x_right_end +beam_width + + # Y positions + y_top = start_y+stiffener_height + flange_thick + y_bottom = (start_y+plate_height) - stiffener_height - flange_thick + + # Left-top horizontal line + self.scene.addLine(x_left_start, y_top, x_left_end, y_top, pen) + + # Left-bottom horizontal line + self.scene.addLine(x_left_start, y_bottom, x_left_end, y_bottom, pen) + + # Right-top horizontal line + self.scene.addLine(x_right_start, y_top, x_right_end, y_top, pen) + + # Right-bottom horizontal line + self.scene.addLine(x_right_start, y_bottom, x_right_end, y_bottom, pen) + self.view.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) + pen = QPen(QColor("black")) + pen.setWidth(2) + offset_len = 25 # 25mm offset for both lines + +# Coordinates for the top-left corner of the left plate + pen = QPen(Qt.black, 2) + pen2=QPen(Qt.black, 1) + brush = QBrush(Qt.NoBrush) + half_thick = stiffener_thickness / 2.0 + # === TOP LEFT === + x1, y1 = start_x, start_y + x2, y2 = start_x - offset_len, start_y + x3, y3 = start_x - stiffener_width, start_y + stiffener_height - offset_len + x4, y4 = start_x - stiffener_width, start_y + stiffener_height + x5, y5 = start_x, start_y + stiffener_height + points_tl = [QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3), QPointF(x4, y4), QPointF(x5, y5)] + polygon_tl = QGraphicsPolygonItem(QPolygonF(points_tl)) + polygon_tl.setPen(pen) + polygon_tl.setBrush(brush) + self.scene.addItem(polygon_tl) + # Red cap + x6, y6 = x5, y5 - half_thick + x7, y7 = x4, y4 - half_thick + polygon_tl = QGraphicsPolygonItem(QPolygonF([QPointF(x4, y4), QPointF(x5, y5), QPointF(x6, y6), QPointF(x7, y7)])) + polygon_tl.setPen(pen) + polygon_tl.setBrush(red_brush) + self.scene.addItem(polygon_tl) + # === BOTTOM LEFT === + x1, y1 = start_x, start_y + plate_height + x2, y2 = start_x - offset_len, start_y + plate_height + x3, y3 = start_x - stiffener_width, start_y + plate_height - stiffener_height + offset_len + x4, y4 = start_x - stiffener_width, start_y + plate_height - stiffener_height + x5, y5 = start_x, start_y + plate_height - stiffener_height + points_bl = [QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3), QPointF(x4, y4), QPointF(x5, y5)] + polygon_bl = QGraphicsPolygonItem(QPolygonF(points_bl)) + polygon_bl.setPen(pen) + polygon_bl.setBrush(brush) + self.scene.addItem(polygon_bl) + # Red cap + x6, y6 = x5, y5 + half_thick + x7, y7 = x4, y4 + half_thick + polygon_tl = QGraphicsPolygonItem(QPolygonF([QPointF(x4, y4), QPointF(x5, y5), QPointF(x6, y6), QPointF(x7, y7)])) + polygon_tl.setPen(pen) + polygon_tl.setBrush(red_brush) + self.scene.addItem(polygon_tl) + # === TOP RIGHT === + x1, y1 = start_x + 2 * plate_thickness, start_y + x2, y2 = x1 + offset_len, start_y + x3, y3 = x1 + stiffener_width, start_y + stiffener_height - offset_len + x4, y4 = x1 + stiffener_width, start_y + stiffener_height + x5, y5 = x1, start_y + stiffener_height + points_tr = [QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3), QPointF(x4, y4), QPointF(x5, y5)] + polygon_tr = QGraphicsPolygonItem(QPolygonF(points_tr)) + polygon_tr.setPen(pen) + polygon_tr.setBrush(brush) + self.scene.addItem(polygon_tr) + # Red cap + x6, y6 = x5, y5 - half_thick + x7, y7 = x4, y4 - half_thick + polygon_tl = QGraphicsPolygonItem(QPolygonF([QPointF(x4, y4), QPointF(x5, y5), QPointF(x6, y6), QPointF(x7, y7)])) + polygon_tl.setPen(pen) + polygon_tl.setBrush(red_brush) + self.scene.addItem(polygon_tl) + # === BOTTOM RIGHT === + x1, y1 = start_x + 2 * plate_thickness, start_y + plate_height + x2, y2 = x1 + offset_len, y1 + x3, y3 = x1 + stiffener_width, start_y + plate_height - stiffener_height + offset_len + x4, y4 = x1 + stiffener_width, start_y + plate_height - stiffener_height + x5, y5 = x1, start_y + plate_height - stiffener_height + points_br = [QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3), QPointF(x4, y4), QPointF(x5, y5)] + polygon_br = QGraphicsPolygonItem(QPolygonF(points_br)) + polygon_br.setPen(pen) + polygon_br.setBrush(brush) + self.scene.addItem(polygon_br) + # Red cap + x6, y6 = x5, y5 + half_thick + x7, y7 = x4, y4 + half_thick + polygon_tl = QGraphicsPolygonItem(QPolygonF([QPointF(x4, y4), QPointF(x5, y5), QPointF(x6, y6), QPointF(x7, y7)])) + polygon_tl.setPen(pen) + polygon_tl.setBrush(red_brush) + self.scene.addItem(polygon_tl) + self.addHorizontalDimension(start_x,start_y-40,start_x-stiffener_width,start_y-40,str(stiffener_width),blackpen) + xpos=start_x +2*plate_thickness +stiffener_width+20 + self.addVerticalDimension(xpos,start_y,xpos,start_y+stiffener_height,str(stiffener_height),blackpen) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(10) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(10) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) \ No newline at end of file diff --git a/src/osdag/gui/baseplatedetailing.py b/src/osdag/gui/baseplatedetailing.py new file mode 100644 index 000000000..48c949353 --- /dev/null +++ b/src/osdag/gui/baseplatedetailing.py @@ -0,0 +1,611 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene,QGraphicsRectItem) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont,QColor +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class BasePlateDetailing(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + self.connection = connection_obj + data=main.output_values(main,True) + print(type(main)) + + bp_width_provided=main.bp_width_provided + column_bf=main.column_bf + effective_length_flange=self.connection.effective_length_flange + plate_thk_provided=main.plate_thk_provided + column_tw=main.column_tw + columnflange_tf=main.column_tf + effective_length_web=self.connection.effective_length_web + plate_thk_provided=main.plate_thk_provided + column_D=main.column_D + print(f'Connectivity : {main.connectivity}\n\n') + # print(data) + print(f""" + bp_width_provided: {bp_width_provided} + column_bf: {column_bf} + effective_length_flange: {effective_length_flange} + plate_thk_provided: {plate_thk_provided} + column_tw: {column_tw}\\column thickness + effective_length_web: {effective_length_web} + column_D:{column_D} + col thickness : {columnflange_tf} + """) + # for i in data: + # print(i) + self.column_len=column_D + self.column_width=column_bf + self.web_thickness=column_tw + self.column_thickness=columnflange_tf + self.detail_dict = { + f'{entry[1]} + {entry[0]}': entry[3] + for entry in data + } + for i in self.detail_dict.keys(): + print(i) + self.no_outsidebolts=self.detail_dict['No. of Anchors + Anchor Bolt.No of Anchor Bolts'] + self.dia_outside_bolt=self.detail_dict['Diameter (mm) + Anchor Bolt.Diameter'] + self.no_insidebolts=self.detail_dict['No. of Anchors + Anchor Bolt.No of Anchor Bolts_Uplift'] + self.dia_inside_bolt=self.detail_dict['Diameter (mm) + Anchor Bolt.Diameter_Uplift'] + self.plate_length=self.detail_dict['Length (mm) + Baseplate.Length'] + self.plate_width=self.detail_dict['Width (mm) + Baseplate.Width'] + self.Endout=self.detail_dict['End Distance (mm) + Detailing.EndDistanceOut'] + self.Edgeout=self.detail_dict['Edge Distance (mm) + Detailing.EdgeDistanceOut'] + self.pitchout=self.detail_dict['Pitch Distance (mm) + Detailing.PitchDistanceOut'] + self.Gaugeout=self.detail_dict['Gauge Distance (mm) + Detailing.GaugeDistanceOut'] + self.Endin=self.detail_dict['End Distance (mm) + Detailing.EndDistanceIn'] + self.Edgein=self.detail_dict['Edge Distance (mm) + Detailing.EdgeDistanceIn'] + self.pitchin=self.detail_dict['Pitch Distance (mm) + Detailing.PitchDistanceIn'] + self.Gaugein=self.detail_dict['Gauge Distance (mm) + Detailing.GaugeDistanceIn'] + + stiffacrossdata=main.stiffener_across_web_details(main,True) + + stiffalongdata=main.stiffener_along_web_details(main,True) + + stiffflangedata=main.stiffener_flange_details(main,True) + self.stiff_across_length=stiffacrossdata[0][3] + self.stiff_across_thickness=stiffacrossdata[2][3] + self.stiff_along_length=stiffalongdata[0][3] + self.stiff_along_thickness=stiffalongdata[2][3] + self.stiff_flange_length=stiffflangedata[0][3] + self.stiff_flange_thickness=stiffflangedata[2][3] + + self.rows = rows + self.cols = cols + self.initUI() + + def initUI(self): + if self.stiff_along_length!='N/A': + self.column_len=(self.plate_length-2*self.column_thickness-2*self.stiff_along_length) + self.setWindowTitle('Bolt Pattern Generator') + print(f""" + Base Plate & Bolt Details: + -------------------------- + No. of Outside Bolts : {self.no_outsidebolts} + Diameter Outside Bolt: {self.dia_outside_bolt} + No. of Inside Bolts : {self.no_insidebolts} + Diameter Inside Bolt : {self.dia_inside_bolt} + Base Plate Length : {self.plate_length} + Base Plate Width : {self.plate_width} + End Distance : {self.Endout} + Edge Distance : {self.Edgeout} + + Stiffener Plate Dimensions: + --------------------------- + Across Web - Length: {self.stiff_across_length}, Thickness: {self.stiff_across_thickness} + Along Web - Length: {self.stiff_along_length}, Thickness: {self.stiff_along_thickness} + Flange - Length: {self.stiff_flange_length}, Thickness: {self.stiff_flange_thickness} + """) + self.setGeometry(100, 100, 800, 500) + # Step 1: Create a central widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # Step 2: Create main layout + main_layout = QHBoxLayout() + central_widget.setLayout(main_layout) + + # Step 3: Left panel for selected labels only + left_panel = QWidget() + left_layout = QVBoxLayout() + left_panel.setLayout(left_layout) + + # Only display selected keys + keys_to_display = [ + + ] + + # Add labels + + # Step 4: Graphics view and scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Background and test shape (optional) + self.scene.setBackgroundBrush(Qt.white) + + # Step 5: Add to main layout + main_layout.addWidget(self.view, stretch=2) + + # Step 6: Call parameter extraction and drawing + # self.get_parameters() + self.createDrawing() + if self.plate_length>700: + self.view.resetTransform() + self.view.scale(0.5, 0.5) + def createDrawing(self): + from PyQt5.QtGui import QColor + try: + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + except (TypeError, ValueError): + print("Invalid plate dimensions") + return + rect = QRectF(0, 0, plate_length, plate_width) + column_len=self.column_len + column_width=self.column_width + flange_thickness=self.column_thickness + web_thickness=self.web_thickness + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(Qt.black) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush(Qt.NoBrush)) + + # Add rectangle to the scene + self.scene.addItem(rect_item) + # Extract parameters + + outline_pen=QPen(Qt.black) + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, plate_length, plate_width)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(Qt.white)) + self.scene.addItem(rect_item) + outline_pen = QPen(QColor("orange")) + # === Center of the base plate === + center_x = plate_length / 2 + center_y = plate_width / 2 + web_top_y=center_y-web_thickness/2 + web_bot_y=center_y+web_thickness/2 + web_left_x=center_x-column_len/2 + web_right_x=center_x+column_len/2 + self.scene.addLine(web_left_x,web_top_y,web_right_x,web_top_y,outline_pen) + self.scene.addLine(web_left_x,web_bot_y,web_right_x,web_bot_y,outline_pen) + #LEFT FLANGE + left_x=web_left_x-flange_thickness + right_x=web_left_x + top_y=center_y-column_width/2 + bot_y=center_y+column_width/2 + junctiontop_y=web_top_y + junctionbot_y=web_bot_y + #1 + self.scene.addLine(left_x,bot_y,left_x,top_y,outline_pen) + self.scene.addLine(left_x,top_y,right_x,top_y,outline_pen) + self.scene.addLine(right_x,top_y,right_x,junctiontop_y,outline_pen) + self.scene.addLine(right_x,junctionbot_y,right_x,bot_y,outline_pen) + self.scene.addLine(right_x,bot_y,left_x,bot_y,outline_pen) + # === RIGHT FLANGE === + left_x = web_right_x # Inner edge (adjacent to web) + right_x = web_right_x + flange_thickness # Outer edge of flange + top_y = center_y - column_width / 2 + bot_y = center_y + column_width / 2 + junctiontop_y = web_top_y + junctionbot_y = web_bot_y + + # 1. Right vertical line + self.scene.addLine(right_x, bot_y, right_x, top_y, outline_pen) + + # 2. Top horizontal line + self.scene.addLine(right_x, top_y, left_x, top_y, outline_pen) + + # 3. Left vertical line (top segment above web) + self.scene.addLine(left_x, top_y, left_x, junctiontop_y, outline_pen) + + # 4. Left vertical line (bottom segment below web) + self.scene.addLine(left_x, junctionbot_y, left_x, bot_y, outline_pen) + + # 5. Bottom horizontal line + self.scene.addLine(left_x, bot_y, right_x, bot_y, outline_pen) + red_brush = QBrush(Qt.red) + outline_pen = QPen(Qt.blue) + outline_pen.setWidth(2) + if isinstance(self.stiff_flange_length, (int, float)): + print('her') + stiff_thk = self.stiff_flange_thickness + offset = (stiff_thk - flange_thickness) / 2 + + # === Left Flange Stiffeners === + # Top stiffener (left) + left_x=web_left_x-flange_thickness + stiffener_left_top = QRectF( + left_x - offset, # shift outward from flange face + 0, # top of plate + stiff_thk, + top_y # height to top of flange + ) + self.scene.addRect(stiffener_left_top, outline_pen, red_brush) + + # Bottom stiffener (left) + stiffener_left_bottom = QRectF( + left_x - offset, + bot_y, # just below bottom of flange + stiff_thk, + plate_width - bot_y # height from flange to bottom of plate + ) + self.scene.addRect(stiffener_left_bottom, outline_pen, red_brush) + left_x=web_left_x-flange_thickness + # === Right Flange Stiffeners === + # Top stiffener (right) + stiffener_right_top = QRectF( + right_x - flange_thickness - offset, + 0, + stiff_thk, + top_y + ) + self.scene.addRect(stiffener_right_top, outline_pen, red_brush) + + # Bottom stiffener (right) + stiffener_right_bottom = QRectF( + right_x - flange_thickness - offset, + bot_y, + stiff_thk, + plate_width - bot_y + ) + self.scene.addRect(stiffener_right_bottom, outline_pen, red_brush) + if isinstance(self.stiff_along_thickness, (int, float)): + # Web center X range + web_center_left = plate_length/2 - column_len/2 - flange_thickness + web_center_right = center_x + column_len/2+flange_thickness + offset=(web_thickness-self.stiff_along_thickness)/2 + # Left web stiffener: from left edge to web start + stiffener_web_left = QRectF( + 0, # x-position (starts from left edge of plate) + plate_width / 2 - self.stiff_along_thickness/2+offset , # y-position (top edge of stiffener) + web_center_left , # width (same as before, up to web) + self.stiff_along_thickness # height (from y-position down) + ) + self.scene.addRect(stiffener_web_left, outline_pen, red_brush) + + # Right web stiffener: from web end to right edge + stiffener_web_right = QRectF( + web_center_right, # x-position (starts from web outward) + plate_width / 2 - self.stiff_along_thickness / 2 + offset, # centered vertically + plate_length - web_center_right, # width from web to right edge + self.stiff_along_thickness + ) + self.scene.addRect(stiffener_web_right, outline_pen, red_brush) + + if isinstance(self.stiff_across_thickness, (int, float)): + web_center_left=center_x-self.stiff_across_thickness/2 + web_center_right=center_x+self.stiff_across_thickness/2 + stiffener_web_top = QRectF( + web_center_left, # x + center_y - self.stiff_across_length-web_thickness/2, # y + self.stiff_across_thickness, # width = right - left + self.stiff_across_length # height from top to web + ) + stiffener_web_bot = QRectF( + web_center_left, # x-start + center_y + self.web_thickness/2, # y-start (just below web) + self.stiff_across_thickness, # width + self.stiff_across_length # height to bottom of plate + ) + self.scene.addRect(stiffener_web_top, outline_pen, red_brush) + self.scene.addRect(stiffener_web_bot, outline_pen, red_brush) + bolts=self.no_outsidebolts + hole_dia=self.dia_outside_bolt + radius=hole_dia/2 + #2 rows + #FINDING EFFECTIVE Edge distance + edge=self.Edgeout + end=self.Endout + Gauge=0 + if self.Gaugeout!='N/A': + Gauge=self.Gaugeout + if self.pitchout!='N/A': + pitch=self.pitchout + print(bolts/4,edge,hole_dia) + if bolts/4 ==1: + edge = (plate_length-column_len-2*flange_thickness)/4 + else: + edge=((plate_length-column_len)/2 - flange_thickness - Gauge)/2 + print(edge) + + gold_brush = QBrush(QColor("gold")) + black_pen = QPen(Qt.black) + black_pen.setWidth(2) + for col in range(int(bolts/4)): + x = edge + col * Gauge # horizontal position + + # Top row bolt + y_top = end + self.scene.addEllipse(x - radius, y_top - radius, 2 * radius, 2 * radius, outline_pen) + + # Bottom bolt + y_bot = plate_width - end + self.scene.addEllipse(x - radius, y_bot - radius, 2 * radius, 2 * radius, outline_pen) + for col in range(int(bolts/4)): + x = plate_length - edge - col * Gauge + y_top = end + y_bot = plate_width - end + + self.scene.addEllipse(x - radius, y_top - radius, 2 * radius, 2 * radius, outline_pen) + self.scene.addEllipse(x - radius, y_bot - radius, 2 * radius, 2 * radius, outline_pen) + + bolts=self.no_insidebolts + self.Edgeout=edge + if bolts!=0 and bolts!='N/A' : + hole_dia=self.dia_inside_bolt + radius=hole_dia/2 + #2 rows + #FINDING EFFECTIVE Edge distance + edge=self.Edgein + end=self.Endin + if self.Gaugein!='N/A': + Gauge=self.Gaugein + if self.pitchin!='N/A': + pitch=self.pitchin + + + if bolts==4 and self.stiff_across_thickness!='N/A': + x_mid_left=center_x-self.stiff_across_thickness/2 + x_mid_right=center_x+self.stiff_across_thickness/2 + y_mid_top=center_y-web_thickness/2 + y_mid_bot=center_y+web_thickness/2 + #4 bolts : + x1 = x_mid_left - edge + y1 = y_mid_top - end + self.scene.addEllipse(x1 - radius, y1 - radius, 2 * radius, 2 * radius, outline_pen) + + # Bottom-left bolt + y2 = y_mid_bot + end + self.scene.addEllipse(x1 - radius, y2 - radius, 2 * radius, 2 * radius, outline_pen) + + # Top-right bolt + x2 = x_mid_right + edge + y3 = y_mid_top - end + self.scene.addEllipse(x2 - radius, y3 - radius, 2 * radius, 2 * radius, outline_pen) + + # Bottom-right bolt + y4 = y_mid_bot + end + self.scene.addEllipse(x2 - radius, y4 - radius, 2 * radius, 2 * radius, outline_pen) + elif self.stiff_across_thickness=='N/A' and bolts==2 : + x1=center_x + y1=center_y-end + self.scene.addEllipse(x1 - radius, y1 - radius, 2 * radius, 2 * radius, outline_pen) + y1=center_y+end + self.scene.addEllipse(x1 - radius, y1 - radius, 2 * radius, 2 * radius, outline_pen) + self.addDimensions(black_pen) + def addDimensions(self, pen): + num_bolts = self.no_outsidebolts + edge_x = float(self.Edgeout) + end_y = float(self.Endout) + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + + gauge = 0 + if self.Gaugeout != 'N/A': + gauge = float(self.Gaugeout) + + # Top side bolts + bolt1_x = edge_x + bolt1_y = end_y + bolt2_x = bolt1_x + gauge + bolt2_y = bolt1_y + + # 1. Top - Edge to bolt 1 + self.addHorizontalDimension(0, bolt1_y + 30, bolt1_x, bolt1_y + 30, f"{round(edge_x)} mm", pen) + # 2. Top - Gauge + if num_bolts // 4 == 2: + self.addHorizontalDimension(bolt1_x, bolt1_y - 20, bolt2_x, bolt2_y - 20, f"{round(gauge)} mm", pen) + # 3. Top - Bolt 2 to edge + self.addHorizontalDimension(bolt2_x, bolt2_y + 30, bolt2_x + edge_x, bolt2_y + 30, f"{round(edge_x)} mm", pen) + # 4. Top - Vertical from plate top to bolts + self.addVerticalDimension(bolt1_x + 30, 0, bolt1_x + 30, bolt1_y, f"{round(end_y)} mm", pen) + + # Bottom side bolts + bolt1_y_bot = plate_width - end_y + bolt2_y_bot = bolt1_y_bot + self.addHorizontalDimension(0, bolt1_y_bot + 30, bolt1_x, bolt1_y_bot + 30, f"{round(edge_x)} mm", pen) + if num_bolts // 4 == 2: + self.addHorizontalDimension(bolt1_x, bolt1_y_bot + 20, bolt2_x, bolt2_y_bot + 20, f"{round(gauge)} mm", pen) + self.addHorizontalDimension(bolt2_x, bolt2_y_bot + 30, bolt2_x + edge_x, bolt2_y_bot + 30, f"{round(edge_x)} mm", pen) + self.addVerticalDimension(bolt1_x + 30, bolt1_y_bot, bolt1_x + 30, plate_width, f"{round(end_y)} mm", pen) + + # Left side bolts + bolt2_x_right = plate_length - edge_x + bolt1_x_right = bolt2_x_right - gauge + bolt_y_right = end_y + + # === 1. Right Edge to Bolt 2 + self.addHorizontalDimension( + bolt2_x_right, bolt_y_right + 30, plate_length, bolt_y_right + 30, + f"{round(edge_x)} mm", pen + ) + + # === 2. Gauge (Bolt 1 to Bolt 2) + if num_bolts // 4 == 2: + self.addHorizontalDimension( + bolt1_x_right, bolt_y_right - 20, bolt2_x_right, bolt_y_right - 20, + f"{round(gauge)} mm", pen + ) + + # === 3. Left Edge to Bolt 1 (mirrored) + self.addHorizontalDimension( + bolt1_x_right - edge_x, bolt_y_right + 30, bolt1_x_right, bolt_y_right + 30, + f"{round(edge_x)} mm", pen + ) + + # === 4. Vertical (top edge to bolts) + self.addVerticalDimension( + bolt2_x_right + 30, 0, bolt2_x_right + 30, bolt_y_right, + f"{round(end_y)} mm", pen + ) + # === Bottom-right corner bolts (horizontal gauge line between bolts) + bolt2_x_br = plate_length - edge_x + bolt1_x_br = bolt2_x_br - gauge + bolt_y_br = plate_width - end_y + + # 1. Vertical from bottom edge to bolt row + self.addVerticalDimension( + bolt2_x_br + 30, bolt_y_br, bolt2_x_br + 30, plate_width, + f"{round(end_y)} mm", pen + ) + # 2. Gauge (horizontal between bolts) + if num_bolts // 4 == 2: + self.addHorizontalDimension( + bolt1_x_br, bolt_y_br + 20, bolt2_x_br, bolt_y_br + 20, + f"{round(gauge)} mm", pen + ) + + # 3. Edge distance from left of bolt 1 (mirror) + self.addHorizontalDimension( + bolt1_x_br - edge_x, bolt_y_br + 30, bolt1_x_br, bolt_y_br + 30, + f"{round(edge_x)} mm", pen + ) + + # 4. Edge distance from bolt 2 to plate edge + self.addHorizontalDimension( + bolt2_x_br, bolt_y_br + 30, plate_length, bolt_y_br + 30, + f"{round(edge_x)} mm", pen + ) + center_x=plate_length/2 + center_y=plate_width/2 + web_thickness=self.web_thickness + flange_thickness = self.column_thickness + column_len=self.column_len + column_width=self.column_width + if self.stiff_along_thickness != 'N/A': + #x = 0 to x= center_x -column_len/2 - flange_thickness (horizontal line) , y = center_y - self.stiff_along_thickness/2 + x1 = 0 + x2 = center_x - column_len / 2 - flange_thickness + y = center_y - self.stiff_along_thickness / 2 + + self.addHorizontalDimension(x1, y-30, x2, y-30, f"{round(x2 - x1)} mm", pen) + if self.stiff_across_thickness != 'N/A': + x=center_x-self.stiff_across_thickness/2 + y2=center_y-web_thickness/2 + y1=y2-self.stiff_across_length + self.addVerticalDimension(x+60,y1,x+60,y2,f"{round(y2-y1)}mm" , pen) + if self.stiff_flange_thickness!='N/A': + x=center_x-column_len/2 + 20 + y1=0 + y2=center_y -column_width/2 + self.addVerticalDimension(x,y1,x,y2,f"{round(y2-y1)}mm" , pen) + num_bolts = self.no_insidebolts + if num_bolts!='N/A' and num_bolts!=0: + edge_x = float(self.Edgein) + end_y = float(self.Endin) + if self.stiff_across_thickness!='N/A' and num_bolts==4: + #1 + x1=center_x-edge_x-self.stiff_across_thickness/2 + x2=x1+edge_x + y1=center_y-end_y-web_thickness/2 + y2=y1+end_y + self.addHorizontalDimension(x1, y1-30, x2, y1-30, f"{round(edge_x)} mm", pen) + self.addVerticalDimension(x1-30,y1,x1-30,y2,f"{round(end_y)}",pen) + elif num_bolts==2: + x1=center_x + y1=center_y-end_y-web_thickness/2 + y2=y1+end_y + self.addVerticalDimension(x1-30,y1,x1-30,y2,f"{round(end_y)} mm",pen) + x1=0 + x2=plate_length + y1=0 + self.addHorizontalDimension(x1, y1-40, x2, y1-40, f"{round(x2)} mm", pen) + x1=plate_length + y1=0 + y2=plate_width + self.addVerticalDimension(x1+20,y1,x1+20,y2,f"{round(y2)} mm",pen) + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(10) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(10) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/baseplatedetailinghollow.py b/src/osdag/gui/baseplatedetailinghollow.py new file mode 100644 index 000000000..eb886090a --- /dev/null +++ b/src/osdag/gui/baseplatedetailinghollow.py @@ -0,0 +1,452 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene,QGraphicsRectItem) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont , QColor +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class BasePlateDetailingHollow(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + self.connection = connection_obj + data=main.output_values(main,True) + print(type(main)) + + bp_width_provided=main.bp_width_provided + column_bf=main.column_bf + effective_length_flange=self.connection.effective_length_flange + plate_thk_provided=main.plate_thk_provided + column_tw=main.column_tw + columnflange_tf=main.column_tf + effective_length_web=self.connection.effective_length_web + plate_thk_provided=main.plate_thk_provided + column_D=main.column_D + print(f'Connectivity : {main.connectivity}\n\n') + # print(data) + print(f""" + bp_width_provided: {bp_width_provided} + column_bf: {column_bf} + effective_length_flange: {effective_length_flange} + plate_thk_provided: {plate_thk_provided} + column_tw: {column_tw}\\column thickness + effective_length_web: {effective_length_web} + column_D:{column_D} + col thickness : {columnflange_tf} + """) + # for i in data: + # print(i) + self.column_len=column_D + self.column_width=column_bf + self.web_thickness=column_tw + self.column_thickness=columnflange_tf + self.detail_dict = { + f'{entry[1]} + {entry[0]}': entry[3] + for entry in data + } + for i in self.detail_dict.keys(): + print(f'{i} : {self.detail_dict[i]}') + self.no_outsidebolts=self.detail_dict['No. of Anchors + Anchor Bolt.No of Anchor Bolts'] + self.dia_outside_bolt=self.detail_dict['Diameter (mm) + Anchor Bolt.Diameter'] + self.no_insidebolts=self.detail_dict['No. of Anchors + Anchor Bolt.No of Anchor Bolts_Uplift'] + self.dia_inside_bolt=self.detail_dict['Diameter (mm) + Anchor Bolt.Diameter_Uplift'] + self.plate_length=self.detail_dict['Length (mm) + Baseplate.Length'] + self.plate_width=self.detail_dict['Width (mm) + Baseplate.Width'] + self.Endout=self.detail_dict['End Distance (mm) + Detailing.EndDistanceOut'] + self.Edgeout=self.detail_dict['Edge Distance (mm) + Detailing.EdgeDistanceOut'] + self.pitchout=self.detail_dict['Pitch Distance (mm) + Detailing.PitchDistanceOut'] + self.Gaugeout=self.detail_dict['Gauge Distance (mm) + Detailing.GaugeDistanceOut'] + self.Endin=self.detail_dict['End Distance (mm) + Detailing.EndDistanceIn'] + self.Edgein=self.detail_dict['Edge Distance (mm) + Detailing.EdgeDistanceIn'] + self.pitchin=self.detail_dict['Pitch Distance (mm) + Detailing.PitchDistanceIn'] + self.Gaugein=self.detail_dict['Gauge Distance (mm) + Detailing.GaugeDistanceIn'] + print(f'Column Section : {main.column_section}') + self.column_section=main.column_section + stiffdata=main.stiffener_hollow_details(main,True) + self.stiff_D_len=stiffdata[1][3] + self.stiff_D_thickness=stiffdata[3][3] + self.stiff_B_len=stiffdata[9][3] + self.stiff_B_thickness=stiffdata[11][3] + self.stiff_OD_len=stiffdata[17][3] + self.stiff_OD_thickness=stiffdata[19][3] + for i in stiffdata: + print(i) + + self.rows = rows + self.cols = cols + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + print(f""" + Base Plate & Bolt Details: + -------------------------- + No. of Outside Bolts : {self.no_outsidebolts} + Diameter Outside Bolt: {self.dia_outside_bolt} + No. of Inside Bolts : {self.no_insidebolts} + Diameter Inside Bolt : {self.dia_inside_bolt} + Base Plate Length : {self.plate_length} + Base Plate Width : {self.plate_width} + End Out Distance : {self.Endout} + Edge Out Distance : {self.Edgeout} + End In Distance : {self.Endin} + Edge In Distance : {self.Edgein} + Plate Width : {self.plate_width} + Plate Length : {self.plate_length} + Stiffener Plate Dimensions: + --------------------------- + STIFFENER_D - Length: {self.stiff_D_len}, Thickness: {self.stiff_D_thickness} + STIFFENER B - Length: {self.stiff_B_len}, Thickness: {self.stiff_B_thickness} + STIFFENER OD- Diameter: {self.stiff_OD_len}, Thickness: {self.stiff_OD_thickness} + """) + self.setGeometry(100, 100, 800, 500) + # Step 1: Create a central widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # Step 2: Create main layout + main_layout = QHBoxLayout() + central_widget.setLayout(main_layout) + + # Step 3: Left panel for selected labels only + left_panel = QWidget() + left_layout = QVBoxLayout() + left_panel.setLayout(left_layout) + + # Only display selected keys + keys_to_display = [ + "No. of Outside Bolts", + "Diameter Outside Bolt", + "No. of Inside Bolts", + "Diameter Inside Bolt", + "Base Plate Length", + "Base Plate Width", + "End Out Distance", + "Edge Out Distance", + "End In Distance", + "Edge In Distance", + "STIFFENER_D Length", + "STIFFENER_D Thickness", + "STIFFENER_B Length", + "STIFFENER_B Thickness", + "STIFFENER_OD Diameter", + "STIFFENER_OD Thickness", + "COLUMN WIDTH", + "COLUMN LENGTH" + ] + + + # Add labels + values_to_display = { + "No. of Outside Bolts": self.no_outsidebolts, + "Diameter Outside Bolt": self.dia_outside_bolt, + "Base Plate Length": self.plate_length, + "Base Plate Width": self.plate_width, + "End Distance": self.Endout, + "Edge Distance": self.Edgeout, + "COLUMN WIDTH": self.column_width, + "COLUMN LENGTH":self.column_len + } + + for key in keys_to_display: + if key in values_to_display: + label = QLabel(f"{key}: {values_to_display[key]}") + left_layout.addWidget(label) + # Step 4: Graphics view and scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Background and test shape (optional) + self.scene.setBackgroundBrush(Qt.white) + + # Step 5: Add to main layout + main_layout.addWidget(self.view, stretch=2) + main_layout.addWidget(left_panel, stretch=1) + # Step 6: Call parameter extraction and drawing + # self.get_parameters() + self.createDrawing() + if self.plate_length>600: + self.view.resetTransform() + self.view.scale(0.5, 0.5) + def createDrawing(self): + try: + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + except (TypeError, ValueError): + print("Invalid plate dimensions") + return + rect = QRectF(0, 0, plate_length, plate_width) + column_len=self.column_len + column_width=self.column_width + flange_thickness=self.column_thickness + web_thickness=self.web_thickness + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(Qt.black) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush(Qt.NoBrush)) + + # Add rectangle to the scene + self.scene.addItem(rect_item) + # Extract parameters + outline_pen = QPen(Qt.black) + outline_pen.setWidth(1) + + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, plate_length, plate_width)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(Qt.white)) + self.scene.addItem(rect_item) + outline_pen = QPen(QColor("orange")) + # === Center of the base plate === + center_x = plate_length / 2 + center_y = plate_width / 2 + print(self.column_section) + if self.column_section.startswith(' RHS') or self.column_section.startswith(' SHS'): + col_len=self.column_len + col_width=self.column_width + col_thickness=self.column_thickness + top_left_x = center_x - col_len / 2 + top_left_y = center_y - col_width / 2 + + # Add rectangle + self.scene.addRect(top_left_x, top_left_y, col_len, col_width, outline_pen) + self.scene.addRect(top_left_x+col_thickness, top_left_y+col_thickness, col_len-2*col_thickness, col_width-2*col_thickness, outline_pen) + #innerrectangle + self.addHorizontalDimension( + top_left_x, # x1 + top_left_y - 20, # y above the column + top_left_x + col_len, # x2 + top_left_y - 20, # y2 (same as y1) + f"{col_len} mm", pen + ) + + # Vertical dimension (Width) + self.addVerticalDimension( + top_left_x - 20, # x to the left of column + top_left_y, # y1 (top) + top_left_x - 20, # x2 (same as x1) + top_left_y + col_width, # y2 (bottom) + f"{col_width} mm", pen + ) + stiff_thickness = self.stiff_D_thickness + else: + col_len=self.column_len + col_width=self.column_width + col_thickness=self.column_thickness + top_left_x = center_x - col_len / 2 + top_left_y = center_y - col_width / 2 + self.scene.addEllipse(top_left_x, top_left_y, col_len, col_width, outline_pen) + + # Inner ellipse (hollow cutout) + inner_x = top_left_x + col_thickness + inner_y = top_left_y + col_thickness + inner_len = col_len - 2 * col_thickness + inner_width = col_width - 2 * col_thickness + self.scene.addEllipse(inner_x, inner_y, inner_len, inner_width, outline_pen) + self.addHorizontalDimension( + top_left_x, # x1 + center_y - 20, # y above the column + top_left_x + col_len, # x2 + center_y - 20, # y2 (same as y1) + f"{col_len} mm", pen + ) + stiff_thickness=self.stiff_OD_thickness + outline_pen = QPen(Qt.black) + outline_pen.setWidth(2) + + + stiff_top = 0 # Top of plate + stiff_start_y = center_y - col_width / 2 # col_width/2 above center + stiff_x = center_x - stiff_thickness / 2 # centered left + + # Height from top of plate to start of stiffener + stiff_height = stiff_start_y - stiff_top + + # Draw vertical stiffener rectangle + self.scene.addRect( + stiff_x, + stiff_top, + stiff_thickness, + stiff_height, + outline_pen, + QBrush(Qt.red) # Optional: red fill + ) + stiff_start_y=center_y+col_width/2 + stiff_x=center_x-stiff_thickness/2 + self.scene.addRect( + stiff_x,stiff_start_y, + stiff_thickness, + stiff_height, + outline_pen, + QBrush(Qt.red) + ) + self.addVerticalDimension( + stiff_x + stiff_thickness + 10, # x (offset right) + stiff_start_y, # y1 (top) + stiff_x + stiff_thickness + 10, # x2 (same x) + stiff_start_y + stiff_height, # y2 (bottom) + f"{round(stiff_height)} mm", pen + ) + if self.column_section.startswith(' RHS') or self.column_section.startswith(' SHS'): + stiff_thickness=self.stiff_B_thickness + stiff_x=0 + stiff_start_y=center_y-stiff_thickness/2 + stiff_length=center_x-col_len/2 + stiff_height=stiff_thickness + self.scene.addRect( + stiff_x,stiff_start_y, + stiff_length, + stiff_height, + outline_pen, + QBrush(Qt.red) + ) + self.addHorizontalDimension( + 0, stiff_start_y + 35, # x1, y1 (slightly above the stiffener) + stiff_length, stiff_start_y +35, # x2, y2 (same y-level) + f"{round(stiff_length)} mm", pen + ) + stiff_x=center_x+col_len/2 + self.scene.addRect( + stiff_x,stiff_start_y, + stiff_length, + stiff_height, + outline_pen, + QBrush(Qt.red) + ) + outline_pen = QPen(Qt.blue) + outline_pen.setWidth(2) + bolts=self.no_outsidebolts + hole_dia=self.dia_outside_bolt + edge=self.Edgeout + end=self.Endout + radius=hole_dia/2 + gold_brush = QBrush(QColor("gold")) + x1 = edge + y1 = end + self.scene.addEllipse(x1 - radius, y1 - radius, hole_dia, hole_dia, outline_pen) + self.addHorizontalDimension(0, y1 + 20, x1, y1 + 20, f"{edge} mm", pen) + self.addVerticalDimension(x1 + 20, 0, x1 + 20, y1, f"{end} mm", pen) + + # Top-right bolt + x2 = self.plate_length - edge + y2 = end + self.scene.addEllipse(x2 - radius, y2 - radius, hole_dia, hole_dia, outline_pen) + self.addHorizontalDimension(x2, y2 + 20, self.plate_length, y2 + 20, f"{edge} mm", pen) + self.addVerticalDimension(x2 + 20, 0, x2 + 20, y2, f"{end} mm", pen) + + # Bottom-left bolt + x3 = edge + y3 = self.plate_width - end + self.scene.addEllipse(x3 - radius, y3 - radius, hole_dia, hole_dia, outline_pen) + self.addHorizontalDimension(0, y3 + 20, x3, y3 + 20, f"{edge} mm", pen) + self.addVerticalDimension(x3 + 20, y3, x3 + 20, self.plate_width, f"{end} mm", pen) + + # Bottom-right bolt + x4 = self.plate_length - edge + y4 = self.plate_width - end + self.scene.addEllipse(x4 - radius, y4 - radius, hole_dia, hole_dia, outline_pen) + self.addHorizontalDimension(x4, y4 + 20, self.plate_length, y4 + 20, f"{edge} mm", pen) + self.addVerticalDimension(x4 + 20, y4, x4 + 20, self.plate_width, f"{end} mm", pen) + + self.addHorizontalDimension( + 0, -30, # x1 at left edge, y above plate + self.plate_length, -30, # x2 at right edge, same y + f"{self.plate_length} mm", pen + ) + + # Vertical dimension for plate width (to the left of the plate) + self.addVerticalDimension( + self.plate_length+30, 0, # x left of plate, y1 at top + self.plate_length+30, self.plate_width, # x2 same, y2 at bottom + f"{self.plate_width} mm", pen + ) + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/beam2beamcoverplatedetailing.py b/src/osdag/gui/beam2beamcoverplatedetailing.py new file mode 100644 index 000000000..80223eeec --- /dev/null +++ b/src/osdag/gui/beam2beamcoverplatedetailing.py @@ -0,0 +1,393 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene,QGraphicsRectItem) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont , QColor +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class B2Bcoverplate(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + print(main) + + if main: + web=main[1] + main=main[0] + super().__init__() + self.connection = connection_obj + # return + data=main.output_values(main,True) + print(type(main)) + dict1={i[0] : i[3] for i in data} + + + print("________________________DEBUG________________________") + print(dict1) + print("________________________DEBUG________________________") + + for i in dict1: + print(f'{i} : {dict1[i]}') + if web==True: + self.plate_length=dict1['Web_Plate.Height (mm)'] + self.plate_width=dict1['Web_Plate.Width'] + self.bolt_diameter=dict1['Bolt.Diameter'] + web_capcity=dict1['Web_plate.spacing'][1] + print(web_capcity(main,True)) + data2=web_capcity(main,True) + for i in range(len(data2)): + print(f"{i} : {data2[i]}") + self.pitch=data2[2][3] + self.End=data2[3][3] + self.Gauge=data2[4][3] + self.Edge=data2[5][3] + bolt_cap=dict1['Web Bolt.Capacities'][1] + print(bolt_cap(main,True)) + bolt_cap=bolt_cap(main,True) + elif web==False: + self.plate_length=dict1['Flange_Plate.Width (mm)'] + self.plate_width=dict1['flange_plate.Length'] + self.bolt_diameter=dict1['Bolt.Diameter'] + flange_capcity=dict1['Flange_plate.spacing'][1] + data2=flange_capcity(main,True) + self.pitch=data2[2][3] + self.End=data2[3][3] + self.Gauge=data2[4][3] + self.Edge=data2[5][3] + bolt_cap=dict1['Bolt.Capacities'][1] + print(bolt_cap(main,True)) + bolt_cap=bolt_cap(main,True) + self.cols=bolt_cap[1][3] + self.rows=bolt_cap[2][3]/self.cols + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 800, 500) + + # Print summary (optional debug/log info) + print(f""" + ----------------------------------------- + Plate & Bolt Configuration Summary + ----------------------------------------- + Plate Length : {self.plate_length} mm + Plate Width : {self.plate_width} mm + Bolt Diameter : {self.bolt_diameter} mm + + Bolt Spacing Details: + --------------------- + Pitch Distance : {self.pitch} mm + End Distance : {self.End} mm + Gauge Distance : {self.Gauge} mm + Edge Distance : {self.Edge} mm + + Bolt Arrangement: + ----------------- + Number of Columns : {self.cols} + Number of Rows : {self.rows} + """) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + + # Get parameter dictionary + params = self.get_parameters() + + for key, value in params.items(): + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Right panel: QGraphicsView with Scene + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Determine font and arrow size based on plate size + self.fontsize = 10 + self.arrowsize = 10 + if self.plate_length > 1200 or self.plate_width > 1200: + self.fontsize = 12 + self.arrowsize = 12 + elif self.plate_length > 600 or self.plate_width > 600: + self.fontsize = 7.5 + self.arrowsize = 7.5 + + # Draw bolts and plate + self.createDrawing() + if self.plate_length>1200 or self.plate_width>1200: + self.view.resetTransform() + self.view.scale(0.35, 0.35) + elif self.plate_length>600 or self.plate_width>600: + self.view.resetTransform() + self.view.scale(0.5, 0.5) + # Add panels to layout + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(self.view, 3) + + # Set central widget with main layout + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + # Automatically adjust view to fit scene + def get_parameters(self): + return { + 'Plate Length': self.plate_length, + 'Plate Width': self.plate_width, + 'Bolt Diameter': self.bolt_diameter, + 'Pitch Distance': self.pitch, + 'End Distance': self.End, + 'Gauge Distance': self.Gauge, + 'Edge Distance': self.Edge, + 'Number of Columns': self.cols, + 'Number of Rows': self.rows + } + def createDrawing(self): + try: + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + except (TypeError, ValueError): + print("Invalid plate dimensions") + return + rect = QRectF(0, 0, plate_length, plate_width) + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(Qt.black) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush(Qt.NoBrush)) + + # Add rectangle to the scene + self.scene.addItem(rect_item) + # Extract parameters + outline_pen = QPen(Qt.black) + outline_pen.setWidth(1) + + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, plate_length, plate_width)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(Qt.white)) + self.scene.addItem(rect_item) + # === Center of the base plate === + center_x = plate_length / 2 + center_y = plate_width / 2 + self.addHorizontalDimension( + 0, -30, # x1 at left edge, y above plate + self.plate_length, -30, # x2 at right edge, same y + f"{self.plate_length} mm", pen + ) + + # Vertical dimension for plate width (to the left of the plate) + self.addVerticalDimension( + self.plate_length+30, 0, # x left of plate, y1 at top + self.plate_length+30, self.plate_width, # x2 same, y2 at bottom + f"{self.plate_width} mm", pen + ) + rows=int(self.rows) + cols=int(self.cols) + pitch=self.pitch + gauge=self.Gauge + end=self.End + edge=self.Edge + hole_dia = self.bolt_diameter + radius = hole_dia / 2 + y_center = end # Y position is fixed for top row + # Center row if rows is odd + outline_pen = QPen(Qt.blue) + outline_pen.setWidth(1) + if rows % 2 != 0: + y_center = self.plate_width / 2 + for i in range(cols // 2): + x_center = edge + i * gauge + self.scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + for i in range(cols // 2): + x_center = self.plate_length - edge - i * gauge + self.scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Center bolt if cols is also odd + if cols % 2 != 0: + x_center = self.plate_length / 2 + self.scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Center column if cols is odd (and rows is even) + if cols % 2 != 0 and rows % 2 == 0: + for j in range(rows // 2): + y_center_top = end + j * pitch + y_center_bottom = self.plate_width - end - j * pitch + + x_center = self.plate_length / 2 + self.scene.addEllipse( + x_center - radius, + y_center_top - radius, + hole_dia, + hole_dia, + outline_pen, + ) + self.scene.addEllipse( + x_center - radius, + y_center_bottom - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Draw left half bolts + for row in range(int(rows)): + if row < rows // 2: + y_center = end + row * pitch + else: + row_from_bottom = row - rows // 2 + y_center = self.plate_width - end - row_from_bottom * pitch + + # Left half bolts + for i in range(cols // 2): + x_center = edge + i * gauge + self.scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Right half bolts + for i in range(cols // 2): + x_center = self.plate_length - edge - i * gauge + self.scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + self.addHorizontalDimension( + 0, self.plate_width+10, # x1 at left edge, y above plate + self.Edge, self.plate_width+10, # x2 at right edge, same y + f"{self.Edge} mm", pen + ) + self.addVerticalDimension( + -10, 0, # x left of plate, y1 at top + -10, self.End, # x2 same, y2 at bottom + f"{self.End} mm", pen + ) + self.addHorizontalDimension( + self.Edge-hole_dia/2, 10, + self.Edge+hole_dia/2,10, + f"{hole_dia} mm", pen + ) + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = int(self.arrowsize) + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(int(self.fontsize)) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = int(self.arrowsize) + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(int(self.fontsize)) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/beam2beamcoverplatedetailing_capacity_details.py b/src/osdag/gui/beam2beamcoverplatedetailing_capacity_details.py new file mode 100644 index 000000000..1a7353031 --- /dev/null +++ b/src/osdag/gui/beam2beamcoverplatedetailing_capacity_details.py @@ -0,0 +1,586 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene,QGraphicsRectItem, QFrame) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont, QColor +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width + +try: + pen_style_dash = Qt.PenStyle.DashLine +except AttributeError: + raise RuntimeError("Your PyQt5 version does not support dashed lines via Qt.PenStyle.DashLine. Please update PyQt5.") + +class B2Bcoverplate_capacity_details(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + print(main) + + if main: + self.drawing_type=main[2] + self.web=main[1] + web=main[1] + main=main[0] + super().__init__() + self.connection = connection_obj + # return + data=main.output_values(main,True) + print(type(main)) + dict1={i[0] : i[3] for i in data} + + + + for i in dict1: + print(f'{i} : {dict1[i]}') + + + if web==True: + self.plate_length=dict1['Web_Plate.Height (mm)'] + self.plate_width=dict1['Web_Plate.Width'] + self.bolt_diameter=dict1['Bolt.Diameter'] + web_capcity=dict1['Web_plate.spacing'][1] + print(web_capcity(main,True)) + data2=web_capcity(main,True) + for i in range(len(data2)): + print(f"{i} : {data2[i]}") + self.pitch=data2[2][3] + self.End=data2[3][3] + self.Gauge=data2[4][3] + self.Edge=data2[5][3] + bolt_cap=dict1['Web Bolt.Capacities'][1] + print(bolt_cap(main,True)) + bolt_cap=bolt_cap(main,True) + elif web==False: + self.plate_length=dict1['Flange_Plate.Width (mm)'] + self.plate_width=dict1['flange_plate.Length'] + self.bolt_diameter=dict1['Bolt.Diameter'] + flange_capcity=dict1['Flange_plate.spacing'][1] + data2=flange_capcity(main,True) + self.pitch=data2[2][3] + self.End=data2[3][3] + self.Gauge=data2[4][3] + self.Edge=data2[5][3] + bolt_cap=dict1['Bolt.Capacities'][1] + print(bolt_cap(main,True)) + bolt_cap=bolt_cap(main,True) + + + + #capacity + if web==True and self.drawing_type=="capacity": + #web capacity details + web_capacity_fnc=dict1['section.web_capacities'][1] + web_capacity_val=web_capacity_fnc(main,True) + self.web_capacity_details = {item[1]: float(item[3]) for item in web_capacity_val if item[2] == 'TextBox'} + + #capacity + elif web==False and self.drawing_type=="capacity": + #flange capacity details + flange_capacity_fnc=dict1['section.flange_capacity'][1] + flange_capacity_val=flange_capacity_fnc(main,True) + self.flange_capacity_details={item[1]: float(item[3]) for item in flange_capacity_val if item[2] == 'TextBox'} + + + + + self.cols=bolt_cap[1][3] + self.rows=bolt_cap[2][3]/self.cols + self.initUI() + + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 1050, 500) + + # Print summary (optional debug/log info) + print(f""" + ----------------------------------------- + Plate & Bolt Configuration Summary + ----------------------------------------- + Plate Length : {self.plate_length} mm + Plate Width : {self.plate_width} mm + Bolt Diameter : {self.bolt_diameter} mm + + Bolt Spacing Details: + --------------------- + Pitch Distance : {self.pitch} mm + End Distance : {self.End} mm + Gauge Distance : {self.Gauge} mm + Edge Distance : {self.Edge} mm + + Bolt Arrangement: + ----------------- + Number of Columns : {self.cols} + Number of Rows : {self.rows} + """) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + + # Get parameter dictionary + params = self.get_parameters((self.web,self.drawing_type)) + count=0 + for key, value in params.items(): + if self.web==False and self.drawing_type=="capacity": + param_layout = QHBoxLayout() + space_label = QLabel(' ') + param_label = QLabel(f'{key.title()} (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + # Add a blank label for vertical spacing + left_layout.addWidget(QLabel('')) + elif self.web==True and self.drawing_type=="capacity": + param_layout = QHBoxLayout() + space_label = QLabel(' ') + param_label = QLabel(f'{key.title()} (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + # Add a blank label for vertical spacing + left_layout.addWidget(QLabel('')) + + count+=1 + else: + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Determine font and arrow size based on plate size + self.fontsize = 10 + self.arrowsize = 10 + if self.plate_length > 1200 or self.plate_width > 1200: + self.fontsize = 12 + self.arrowsize = 12 + elif self.plate_length > 600 or self.plate_width > 600: + self.fontsize = 7.5 + self.arrowsize = 7.5 + + if self.web == True and self.drawing_type == "capacity": + # Two drawings, each with its own parameter set, separated by a horizontal line + self.scene1 = QGraphicsScene() + self.view1 = QGraphicsView(self.scene1) + self.view1.setRenderHint(QPainter.Antialiasing) + + self.scene2 = QGraphicsScene() + self.view2 = QGraphicsView(self.scene2) + self.view2.setRenderHint(QPainter.Antialiasing) + + self.createDrawing((self.web, self.drawing_type), self.scene1) + self.createDrawing((self.web, self.drawing_type), self.scene2) + + if self.plate_length > 1200 or self.plate_width > 1200: + self.view1.resetTransform() + self.view1.scale(0.35, 0.35) + self.view2.resetTransform() + self.view2.scale(0.35, 0.35) + elif self.plate_length > 600 or self.plate_width > 600: + self.view1.resetTransform() + self.view1.scale(0.5, 0.5) + self.view2.resetTransform() + self.view2.scale(0.5, 0.5) + + # Split parameters into two groups (first two, next two) + params = list(self.get_parameters((self.web, self.drawing_type)).items()) + params1 = params[:2] + params2 = params[2:] + + # Section 1: first two parameters and first drawing + section1_layout = QHBoxLayout() + section1_text_widget = QWidget() + section1_text_layout = QVBoxLayout(section1_text_widget) + param_label = QLabel('Failure Pattern due to tension in Member and Plate') + param_label.setFont(QFont('Arial',12,QFont.Bold)) + section1_text_layout.addWidget(param_label) + for key, value in params1: + param_label = QLabel(f'{key}: {value}') + section1_text_layout.addWidget(param_label) + section1_text_layout.addStretch() + section1_text_widget.setMinimumWidth(180) + section1_layout.addWidget(section1_text_widget, 1) + section1_layout.addWidget(self.view1, 2) + + # Section 2: next two parameters and second drawing + section2_layout = QHBoxLayout() + section2_text_widget = QWidget() + section2_text_layout = QVBoxLayout(section2_text_widget) + param_label = QLabel('Failure Pattern due to tension in Member and Plate') + param_label.setFont(QFont('Arial',12,QFont.Bold)) + section2_text_layout.addWidget(param_label) + for key, value in params2: + param_label = QLabel(f'{key}: {value}') + section2_text_layout.addWidget(param_label) + section2_text_layout.addStretch() + section2_text_widget.setMinimumWidth(180) + section2_layout.addWidget(section2_text_widget, 1) + section2_layout.addWidget(self.view2, 2) + + # Horizontal line between sections + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + + # Main vertical layout + main_vlayout = QVBoxLayout() + main_vlayout.addLayout(section1_layout) + main_vlayout.addWidget(line) + main_vlayout.addLayout(section2_layout) + + self.view1.setMaximumWidth(400) + self.view2.setMaximumWidth(400) + + main_widget = QWidget() + main_widget.setLayout(main_vlayout) + self.setCentralWidget(main_widget) + else: + # Only one drawing (original layout) + left_panel = QWidget() + left_layout = QVBoxLayout() + params = self.get_parameters((self.web, self.drawing_type)) + for key, value in params.items(): + if self.web==False and self.drawing_type=="capacity": + param_layout = QHBoxLayout() + space_label = QLabel(' ') + param_label = QLabel(f'{key.title()} (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + left_layout.addWidget(QLabel('')) + else: + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + left_layout.addStretch() + left_panel.setLayout(left_layout) + + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + self.createDrawing((self.web, self.drawing_type), self.scene) + + if self.plate_length > 1200 or self.plate_width > 1200: + self.view.resetTransform() + self.view.scale(0.35, 0.35) + elif self.plate_length > 600 or self.plate_width > 600: + self.view.resetTransform() + self.view.scale(0.5, 0.5) + + main_layout = QHBoxLayout() + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(self.view, 3) + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + # Automatically adjust view to fit scene + def get_parameters(self,type_): + if (type_[0]==True and type_[1]=="spacing") or (type_[0]==False and type_[1]=="spacing") : + return { + 'Plate Length': self.plate_length, + 'Plate Width': self.plate_width, + 'Bolt Diameter': self.bolt_diameter, + 'Pitch Distance': self.pitch, + 'End Distance': self.End, + 'Gauge Distance': self.Gauge, + 'Edge Distance': self.Edge, + 'Number of Columns': self.cols, + 'Number of Rows': self.rows + } + elif type_[0]==True and type_[1]=="capacity": + return self.web_capacity_details + elif type_[0]==False and type_[1]=="capacity": + return self.flange_capacity_details + + def createDrawing(self, type_, scene): + + + + try: + plate_length = float(self.plate_length) + plate_width = float(self.plate_width) + except (TypeError, ValueError): + print("Invalid plate dimensions") + return + rect = QRectF(0, 0, plate_length, plate_width) + # Create a rectangle item + rect_item = QGraphicsRectItem(rect) + + # Set pen and brush (black border, transparent fill) + pen = QPen(QColor('black')) + pen.setWidth(2) + rect_item.setPen(pen) + rect_item.setBrush(QBrush()) # Default is NoBrush + + # Add rectangle to the scene + scene.addItem(rect_item) + + + # Extract parameters + outline_pen = QPen(QColor('black')) + outline_pen.setWidth(1) + + # === Draw Base Plate Rectangle === + rect_item = QGraphicsRectItem(QRectF(0, 0, plate_length, plate_width)) + rect_item.setPen(outline_pen) + rect_item.setBrush(QBrush(QColor('white'))) + scene.addItem(rect_item) + dashed_pen = QPen(QColor('black')) + dashed_pen.setStyle(pen_style_dash) + dashed_pen.setWidth(2) + if type_[0]==False and type_[1]=="capacity": + + #top drawing + scene.addLine(self.Edge, 0, self.Edge, self.End, dashed_pen) + + scene.addLine(self.Edge, self.End, plate_length, self.End, dashed_pen) + + + #bottom drawing + scene.addLine(self.Edge, plate_width, self.Edge, plate_width-self.End, dashed_pen) + + scene.addLine(self.Edge, plate_width-self.End, plate_length, plate_width-self.End, dashed_pen) + + elif type_[0]==True and type_[1]=="capacity" and scene==self.scene1: + + scene.addLine(self.End, self.Edge, self.End, plate_width-self.End, dashed_pen) + + scene.addLine(self.End, self.Edge, plate_length, self.Edge, dashed_pen) + + scene.addLine(self.End, plate_width-self.Edge, plate_length, plate_width-self.Edge, dashed_pen) + + + elif type_[0]==True and type_[1]=="capacity" and scene==self.scene2: + + scene.addLine(0, self.Edge, plate_length-self.End, self.Edge, dashed_pen) + + scene.addLine(plate_length-self.End, self.Edge, plate_length-self.End, plate_width, dashed_pen) + + + # === Center of the base plate === + center_x = plate_length / 2 + center_y = plate_width / 2 + self.addHorizontalDimension( + 0, -30, # x1 at left edge, y above plate + self.plate_length, -30, # x2 at right edge, same y + f"{self.plate_length} mm", pen, scene + ) + + # Vertical dimension for plate width (to the left of the plate) + self.addVerticalDimension( + self.plate_length+30, 0, # x left of plate, y1 at top + self.plate_length+30, self.plate_width, # x2 same, y2 at bottom + f"{self.plate_width} mm", pen, scene + ) + + rows=int(self.rows) + cols=int(self.cols) + pitch=self.pitch + gauge=self.Gauge + end=self.End + edge=self.Edge + hole_dia = self.bolt_diameter + radius = hole_dia / 2 + y_center = end # Y position is fixed for top row + # Center row if rows is odd + outline_pen = QPen(QColor('blue')) + outline_pen.setWidth(1) + if rows % 2 != 0: + y_center = self.plate_width / 2 + for i in range(cols // 2): + x_center = edge + i * gauge + scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + for i in range(cols // 2): + x_center = self.plate_length - edge - i * gauge + scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Center bolt if cols is also odd + if cols % 2 != 0: + x_center = self.plate_length / 2 + scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Center column if cols is odd (and rows is even) + if cols % 2 != 0 and rows % 2 == 0: + for j in range(rows // 2): + y_center_top = end + j * pitch + y_center_bottom = self.plate_width - end - j * pitch + + x_center = self.plate_length / 2 + scene.addEllipse( + x_center - radius, + y_center_top - radius, + hole_dia, + hole_dia, + outline_pen, + ) + scene.addEllipse( + x_center - radius, + y_center_bottom - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Draw left half bolts + for row in range(int(rows)): + if row < rows // 2: + y_center = end + row * pitch + else: + row_from_bottom = row - rows // 2 + y_center = self.plate_width - end - row_from_bottom * pitch + + # Left half bolts + for i in range(cols // 2): + x_center = edge + i * gauge + scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + + # Right half bolts + for i in range(cols // 2): + x_center = self.plate_length - edge - i * gauge + scene.addEllipse( + x_center - radius, + y_center - radius, + hole_dia, + hole_dia, + outline_pen, + ) + self.addHorizontalDimension( + 0, self.plate_width+10, # x1 at left edge, y above plate + self.Edge, self.plate_width+10, # x2 at right edge, same y + f"{self.Edge} mm", pen, scene + ) + self.addVerticalDimension( + -10, 0, # x left of plate, y1 at top + -10, self.End, # x2 same, y2 at bottom + f"{self.End} mm", pen, scene + ) + # self.addHorizontalDimension( + # self.Edge-hole_dia/2, 10, + # self.Edge+hole_dia/2,10, + # f"{hole_dia} mm", pen + # ) + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen, scene): + scene.addLine(x1, y1, x2, y2, pen) + arrow_size = int(self.arrowsize) + ext_length = 10 + scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(QColor('black'))) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(QColor('black'))) + + text_item = scene.addText(text) + font = QFont() + font.setPointSize(int(self.fontsize)) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen, scene): + scene.addLine(x1, y1, x2, y2, pen) + arrow_size = int(self.arrowsize) + ext_length = 10 + scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(QColor('black'))) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(QColor('black'))) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(QColor('black'))) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(QColor('black'))) + + text_item = scene.addText(text) + font = QFont() + font.setPointSize(int(self.fontsize)) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) diff --git a/src/osdag/gui/capacity_details_finPlate.py b/src/osdag/gui/capacity_details_finPlate.py new file mode 100644 index 000000000..ad4694aa2 --- /dev/null +++ b/src/osdag/gui/capacity_details_finPlate.py @@ -0,0 +1,444 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +from ..design_type.connection.end_plate_connection import EndPlateConnection + +class CapacityDetailsWindow(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + self.connection = connection_obj + self.main=main + self.plate_height = main.plate.height + self.plate_width = main.plate.length + self.hole_dia=main.bolt.bolt_diameter_provided + self.rows=main.plate.bolts_one_line + self.cols=main.plate.bolt_line + self.plate_thickness=main.plate.thickness + print(self.plate_height,self.plate_width) + output=main.output_values(main,True) + dict1={i[0] : i[3] for i in output} + + capacity_fnc = dict1['button1'][1] + print(capacity_fnc) + capacity_details = capacity_fnc(main,True) + print(capacity_details) + details_dict={i[1]:i[3] for i in capacity_details} + + self.shear_yield_capacity=float(details_dict['Shear Yielding Capacity (kN)']) + self.rupture_capacity=float(details_dict['Rupture Capacity (kN)']) + self.Block_Shear_Capacity=float(details_dict['Block Shear Capacity (kN)']) + self.Tension_Yielding_Capacity=float(details_dict['Tension Yielding Capacity (kN)']) + self.Tension_rupture_Capacity=float(details_dict['Tension Rupture Capacity (kN)']) + self.axial_block_shear_capacity=float(details_dict['Axial Block Shear Capacity (kN)']) + self.moment_demand=float(details_dict['Moment Demand (kNm)']) + self.moment_capacity=float(details_dict['Moment Capacity (kNm)']) + print("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + print("------------------------------------------------------------------") + self.dict_shear_failure={ + 'Shear Yielding Capacity (kN)':self.shear_yield_capacity, + 'Rupture Capacity (kN)':self.rupture_capacity, + 'Block Shear Capacity (kN)':self.Block_Shear_Capacity + } + self.dict_tension_failure={ + 'Tension Yielding Capacity (kN)':self.Tension_Yielding_Capacity, + 'Tension Rupture Capacity (kN)':self.Tension_rupture_Capacity, + 'Axial Block Shear Capacity (kN)':self.axial_block_shear_capacity + } + self.dict_section_3={ + 'Moment Demand (kNm)':self.moment_demand, + 'Moment Capacity (kNm)':self.moment_capacity + } + + print(self.dict_shear_failure) + print(self.dict_tension_failure) + print(self.dict_section_3) + print("------------------------------------------------------------------") + print("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + + for i in output: + print(i) + self.weldsize=0 + if 'Weld.Size' in dict1: + self.weldsize=dict1['Weld.Size'] + self.initUI() + + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 1650, 1050) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + + # Parameter display labels + params = self.get_parameters() + + heading_label = QLabel("Note: Representative image for Failure Pattern (Half Plate)- 2 x 3 Bolts pattern considered") + heading_label.setStyleSheet("font-size: 20px;") + left_layout.addWidget(heading_label) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 25px;") + left_layout.addWidget(space_label) + + sub_heading_label1 = QLabel("Failure Pattern due to Shear in Plate") + sub_heading_label1.setStyleSheet("font-size: 18px; font-weight: bold;") + left_layout.addWidget(sub_heading_label1) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 15px;") + left_layout.addWidget(space_label) + + # Display the parameter values + for key, value in self.dict_shear_failure.items(): + param_layout = QHBoxLayout() + param_label = QLabel(key.title()) + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 5px;") + left_layout.addWidget(space_label) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 25px;") + left_layout.addWidget(space_label) + + sub_heading_label2 = QLabel("Failure Pattern due to Tension in Plate") + sub_heading_label2.setStyleSheet("font-size: 18px; font-weight: bold;") + left_layout.addWidget(sub_heading_label2) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 15px;") + left_layout.addWidget(space_label) + + for key, value in self.dict_tension_failure.items(): + param_layout = QHBoxLayout() + param_label = QLabel(key.title()) + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 5px;") + left_layout.addWidget(space_label) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 25px;") + left_layout.addWidget(space_label) + + sub_heading_label3 = QLabel("Section 3") + sub_heading_label3.setStyleSheet("font-size: 18px; font-weight: bold;") + left_layout.addWidget(sub_heading_label3) + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 15px;") + left_layout.addWidget(space_label) + + for key, value in self.dict_section_3.items(): + param_layout = QHBoxLayout() + param_label = QLabel(key.title()) + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 5px;") + left_layout.addWidget(space_label) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Right panel for the two vertical drawings + right_panel = QWidget() + right_layout = QVBoxLayout() + right_panel.setLayout(right_layout) + + sub_heading_label1 = QLabel("Failure Pattern due to Shear in Plate:") + sub_heading_label1.setStyleSheet("font-size: 16px; font-weight: bold;") + right_layout.addWidget(sub_heading_label1) + + # First drawing + self.scene1 = QGraphicsScene() + self.view1 = QGraphicsView(self.scene1) + self.view1.setRenderHint(QPainter.Antialiasing) + self.createDrawing(self.scene1) + self.view1.fitInView(self.scene1.sceneRect(), Qt.KeepAspectRatio) + right_layout.addWidget(self.view1) + + + space_label=QLabel(" ") + space_label.setStyleSheet("font-size: 15px;") + right_layout.addWidget(space_label) + + sub_heading_label2 = QLabel("Failure Pattern due to Tension in Plate:") + sub_heading_label2.setStyleSheet("font-size: 16px; font-weight: bold;") + right_layout.addWidget(sub_heading_label2) + + # Second drawing (identical to first) + self.scene2 = QGraphicsScene() + self.view2 = QGraphicsView(self.scene2) + self.view2.setRenderHint(QPainter.Antialiasing) + self.createSecondDrawing(self.scene2) # Using the same drawing function + self.view2.fitInView(self.scene2.sceneRect(), Qt.KeepAspectRatio) + right_layout.addWidget(self.view2) + + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(right_panel, 3) + + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + def get_parameters(self): + spacing_data = self.connection.spacing(status=True) # Get actual values + param_map = {} + print('spacing_data length' , len(spacing_data)) + for item in spacing_data: + key, _, _, value = item + if key == KEY_OUT_PITCH: + param_map['pitch'] = float(value) + elif key == KEY_OUT_END_DIST: + param_map['end'] = float(value) + elif key == KEY_OUT_GAUGE1: + param_map['gauge1'] = float(value) + elif key == KEY_OUT_GAUGE2: + param_map['gauge2'] = float(value) + elif key == KEY_OUT_GAUGE: + param_map['gauge'] = float(value) + elif key == KEY_OUT_EDGE_DIST: + param_map['edge'] = float(value) + + # Add hardcoded hole diameter + param_map['hole'] = self.main.bolt.bolt_diameter_provided + + print("Extracted parameters:", param_map) + return param_map + + +# failure due to shear in plate + def createDrawing(self, scene): + coeff = 2 # scaling coefficient + params = self.get_parameters() + pitch = params['pitch'] / coeff + end = params['end'] / coeff + if 'gauge' in params: + gauge1 = gauge2 = params['gauge'] / coeff + else: + gauge1 = params['gauge1'] / coeff + gauge2 = params['gauge2'] / coeff + edge = params['edge'] / coeff + width = self.plate_width / coeff + height = self.plate_height / coeff + hole_diameter = params['hole'] / coeff + weld_size = self.weldsize / coeff + + outline_pen = QPen(Qt.blue, 2/coeff) + dimension_pen = QPen(Qt.black, 1.5/coeff) + red_brush = QBrush(Qt.red) + + # Create dashed pen for failure patterns + dashed_pen = QPen(Qt.black, 1.5/coeff, Qt.DashLine) + + + + h_offset = 40 / coeff + v_offset = 60 / coeff + scene.setSceneRect(-h_offset, -v_offset, width + 2*v_offset, height + 2*h_offset) + #adding the shear failure pattern + scene.addLine(width-end, 0, width-end, height-edge, dashed_pen) + scene.addLine(0, height-edge, width-end, height-edge, dashed_pen) + scene.addRect(0, 0, width, height, dimension_pen) + + # Draw holes + for row in range(self.rows): + for col in range(self.cols): + x_center = width - edge + for i in range(col): + x_center -= gauge1 if i % 2 == 0 else gauge2 + y_center = end + row * pitch + x = x_center - hole_diameter / 2 + y = y_center - hole_diameter / 2 + scene.addEllipse(x, y, hole_diameter, hole_diameter, outline_pen) + # Draw weld area + if weld_size > 0: + scene.addRect(0, 0, weld_size, height, dimension_pen, red_brush) + # Add dimensions + self.addDimensions(scene, width, height, pitch, end, gauge1, gauge2, edge, dimension_pen, coeff) + + + def createSecondDrawing(self, scene): + coeff = 2 # scaling coefficient + params = self.get_parameters() + pitch = params['pitch'] / coeff + end = params['end'] / coeff + if 'gauge' in params: + gauge1 = gauge2 = params['gauge'] / coeff + else: + gauge1 = params['gauge1'] / coeff + gauge2 = params['gauge2'] / coeff + edge = params['edge'] / coeff + width = self.plate_width / coeff + height = self.plate_height / coeff + hole_diameter = params['hole'] / coeff + weld_size = self.weldsize / coeff + + outline_pen = QPen(Qt.blue, 2/coeff) + dimension_pen = QPen(Qt.black, 1.5/coeff) + red_brush = QBrush(Qt.red) + + # Create dashed pen for failure patterns + dashed_pen = QPen(Qt.black, 1.5/coeff, Qt.DashLine) + + + + + if self.cols==1: + x_line_dist=width-end + else: + x_line_dist=width-end - (self.cols-1)*gauge1 + + h_offset = 40 / coeff + v_offset = 60 / coeff + scene.setSceneRect(-h_offset, -v_offset, width + 2*v_offset, height + 2*h_offset) + #adding the tension failure pattern + scene.addLine(x_line_dist, edge, width, edge, dashed_pen) + scene.addLine(x_line_dist, edge, x_line_dist, height-edge, dashed_pen) + scene.addLine(x_line_dist, height-edge, width, height-edge, dashed_pen) + scene.addRect(0, 0, width, height, dimension_pen) + + + # Draw holes + for row in range(self.rows): + for col in range(self.cols): + x_center = width - edge + for i in range(col): + x_center -= gauge1 if i % 2 == 0 else gauge2 + y_center = end + row * pitch + x = x_center - hole_diameter / 2 + y = y_center - hole_diameter / 2 + scene.addEllipse(x, y, hole_diameter, hole_diameter, outline_pen) + # Draw weld area + if weld_size > 0: + scene.addRect(0, 0, weld_size, height, dimension_pen, red_brush) + # Add dimensions + self.addDimensions(scene, width, height, pitch, end, gauge1, gauge2, edge, dimension_pen, coeff) + + + + def addDimensions(self, scene, width, height, pitch, end, gauge1, gauge2, edge, pen, coeff): + h_offset = 20 / coeff + v_offset = 30 / coeff + x_start = width + segments = [] + segments.append(('edge', x_start-edge, x_start)) + x_start -= edge + segments.append(('edge', 0, x_start)) + for label, x1, x2 in segments: + value = x2 - x1 + self.addHorizontalDimension(scene, x1, -h_offset, x2, -h_offset, f"{value:.1f}", pen) + # Add vertical dimensions + self.addVerticalDimension(scene, width + v_offset, 0, width + v_offset, end, str(end), pen) + for i in range(self.rows - 1): + self.addVerticalDimension(scene, width + v_offset, end + i * pitch, + width + v_offset, end + (i + 1) * pitch, str(pitch), pen) + self.addVerticalDimension(scene, width + v_offset, height, width + v_offset, height - end, str(end), pen) + total_height = 2 * end + (self.rows - 1) * pitch + self.addVerticalDimension(scene, -v_offset, 0, -v_offset, total_height, str(total_height), pen) + + def addHorizontalDimension(self, scene, x1, y1, x2, y2, text, pen): + scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 2 + ext_length = 10 + scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = scene.addText(text) + font = QFont() + font.setPointSize(2) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, scene, x1, y1, x2, y2, text, pen): + scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 2 + ext_length = 10 + scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = scene.addText(text) + font = QFont() + font.setPointSize(2) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) \ No newline at end of file diff --git a/src/osdag/gui/cleatangledetailing.py b/src/osdag/gui/cleatangledetailing.py new file mode 100644 index 000000000..7684e2970 --- /dev/null +++ b/src/osdag/gui/cleatangledetailing.py @@ -0,0 +1,299 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class CleatAngle(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + (main,self.flag)=main + spacing_data = connection_obj.spacing(status=True) + output=connection_obj.output_values(True) + data1={ f'{i[1]} + {i[0]}' : i[3] for i in output} + + self.angle_thickness=float(data1['Cleat Angle Designation + Cleat.Angle'].split(" ")[-1]) + + params= { + 'width' : int(data1['Height (mm) + Plate.Height']), + 'hole' : int(data1['Diameter (mm) + Bolt.Diameter']), + } + if self.flag==0: + params['length']=int(data1['Cleat Angle Designation + Cleat.Angle'][0:2]) + params['rows']=int(data1['Bolt Rows (nos) + Bolt.OneLine']) + params['cols']=int(data1['Bolt Columns (nos) + Bolt.Line']) + else: + params['length']=int(data1['Cleat Angle Designation + Cleat.Angle'][5:7]) + params['rows']=int(data1['Bolt Rows (nos) + Cleat.Spting_leg.OneLine']) + params['cols']=int(data1['Bolt Columns (nos) + Cleat.Spting_leg.Line']) + for i in spacing_data: + print(i) + for item in spacing_data: + if not isinstance(item[0], str): + continue + key = item[0].lower() + value = item[3] + + if 'pitch' in key: + params['pitch'] = value + elif 'gauge1' in key: + params['gauge1'] = value + elif 'gauge2' in key: + params['gauge2'] = value + elif 'end' in key: + params['end']=value + elif 'edge' in key: + params['edge']=value + for i in params: + print(f'{i} : {params[i]}') + self.params=params + self.initUI() + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 1000, 600) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + + # Parameter display labels + params = self.params + + # Display the parameter values + for key, value in params.items(): + if key=='cols' or key=='rows' or key=='hole' or key=='length' or key=='width': + continue + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} Distance (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Right panel for the drawing using QGraphicsView + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Create and add the drawing to the scene + self.createDrawing(params) + + # Add panels to main layout + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(self.view, 3) + + # Set main widget + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + # Ensure the view shows all content + self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) + + def createDrawing(self, params): + + # Extract parameters + pitch = params['pitch'] + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + else: + gauge1 = params['gauge1'] + gauge2 = params['gauge2'] + edge = params['edge'] + hole_diameter = params['hole'] + self.rows=params['rows'] + self.cols=params['cols'] + + # Calculate dimensions + if 'gauge' in params: + gauge1 = gauge + gauge2 = gauge + width = params['length'] + + height = params['width'] + self.plate_width=width + self.plate_height=height + # Set up pens + outline_pen = QPen(Qt.blue, 2) + dimension_pen = QPen(Qt.black, 1.5) + angle_pen = QBrush(Qt.red) + + # Dimension offsets + h_offset = 40 + v_offset = 60 + + # Create scene rectangle with extra space for dimensions + self.scene.setSceneRect(-h_offset, -v_offset, + width + 2*v_offset, height + 2*h_offset) + + # Draw rectangle + self.scene.addRect(0, 0, width, height, dimension_pen) + self.scene.addRect(0, 0, self.angle_thickness, height, dimension_pen, angle_pen) + + + # Draw holes + for row in range(self.rows): + for col in range(self.cols): + # Start from right edge (for example: total plate width - edge) + x_center = self.plate_width - edge + + # Subtract gauges from right to left + for i in range(col): + x_center -= gauge1 if i % 2 == 0 else gauge2 + + # Y-position stays the same + y_center = end + row * pitch + + # Top-left corner for drawing the circle + x = x_center - hole_diameter / 2 + y = y_center - hole_diameter / 2 + + print(f"row: {row}, col: {col}, x: {x}, y: {y}") + self.scene.addEllipse(x, y, hole_diameter, hole_diameter, outline_pen) + + print(params,dimension_pen) + # Add dimensions + self.addDimensions(params, dimension_pen) + + def addDimensions(self, params, pen): + # Extract parameters + pitch = params['pitch'] + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + else: + gauge1 = params['gauge1'] + gauge2 = params['gauge2'] + edge = params['edge'] + + if 'gauge' in params: + gauge1 = gauge + gauge2 = gauge + + width = self.plate_width + height = self.plate_height + + # Offsets for dimension lines + h_offset = 20 + v_offset = 30 + + # Add horizontal dimensions + x_start = width + segments = [] + # First edge + segments.append(('edge', x_start-edge, x_start )) + x_start -=edge + + # Last edge + segments.append(('edge', 0, x_start)) + + # Draw each segment + for label, x1, x2 in segments: + value = x2 - x1 + self.addHorizontalDimension(x1, -h_offset, x2, -h_offset, f"{value:.1f}", pen) + # Add vertical dimensions + self.addVerticalDimension(width + v_offset, 0, width + v_offset, end, str(end), pen) + for i in range(self.rows - 1): + self.addVerticalDimension(width + v_offset, end + i * pitch, width + v_offset, end + (i + 1) * pitch, str(pitch), pen) + + # Add bottom end distance dimension + self.addVerticalDimension(width + v_offset, height, width + v_offset, height - end, str(end), pen) + + # Add left side dimension + total_height = 2 * end + (self.rows - 1) * pitch + self.addVerticalDimension(-v_offset, 0, -v_offset, total_height, str(total_height), pen) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) \ No newline at end of file diff --git a/src/osdag/gui/endplatecnndetailnig.py b/src/osdag/gui/endplatecnndetailnig.py new file mode 100644 index 000000000..35316e7f7 --- /dev/null +++ b/src/osdag/gui/endplatecnndetailnig.py @@ -0,0 +1,303 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +from ..design_type.connection.end_plate_connection import EndPlateConnection + +class EndPlateDetailer(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + self.connection = connection_obj + self.main=main + output=main.output_values(main,True) + dict1={i[0] : i[3] for i in output} + self.plate_height = dict1['Plate.Height'] + self.plate_width = dict1['Plate.Length'] + self.hole_dia=dict1['Bolt.Diameter'] + self.rows=dict1['Bolt.Rows'] + self.cols=main.plate.bolt_line + print(self.cols) + for i in output: + print(i) + self.weldsize=0 + if 'Weld.Size' in dict1: + self.weldsize=dict1['Weld.Size'] + print(main.supported_section.web_thickness) + self.weldgap=main.supported_section.web_thickness + self.initUI() + # print(self.connection.spacing(status=True)) + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 1200, 800) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + + # Parameter display labels + params = self.get_parameters() + + # Display the parameter values + for key, value in params.items(): + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} Distance (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Right panel for the drawing using QGraphicsView + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Create and add the drawing to the scene + self.createDrawing(params) + + # Add panels to main layout + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(self.view, 3) + + # Set main widget + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + # Ensure the view shows all content + self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) + def get_parameters(self): + spacing_data = self.connection.spacing(status=True) # Get actual values + param_map = {} + print('spacing_data length' , len(spacing_data)) + for item in spacing_data: + key, _, _, value = item + # print('key : ', key) + if key == KEY_OUT_PITCH: + param_map['pitch'] = float(value) + elif key == KEY_OUT_END_DIST: + param_map['end'] = float(value) + elif key == KEY_OUT_GAUGE1: + param_map['gauge1'] = float(value) + elif key == KEY_OUT_GAUGE2: + param_map['gauge2'] = float(value) + elif key == KEY_OUT_GAUGE: + param_map['gauge'] = float(value) + elif key == KEY_OUT_EDGE_DIST: + param_map['edge'] = float(value) + + # Add hardcoded hole diameter + param_map['hole'] = self.main.bolt.bolt_diameter_provided + + print("Extracted parameters:", param_map) + + return param_map + + def createDrawing(self, params): + + # Extract parameters + pitch = params['pitch'] + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + else: + gauge1 = params['gauge1'] + gauge2 = params['gauge2'] + edge = params['edge'] + hole_diameter = params['hole'] + + # Calculate dimensions + if 'gauge' in params: + gauge1 = gauge + gauge2 = gauge + width = self.plate_width + + height = self.plate_height + + # Set up pens + outline_pen = QPen(Qt.blue, 2) + dimension_pen = QPen(Qt.black, 1.5) + red_brush = QBrush(Qt.red) + + # Dimension offsets + h_offset = 40 + v_offset = 60 + + # Create scene rectangle with extra space for dimensions + self.scene.setSceneRect(-h_offset, -v_offset, + width + 2*v_offset, height + 2*h_offset) + + # Draw rectangle + self.scene.addRect(0, 0, width, height, dimension_pen) + + # Draw holes + for row in range(self.rows): + for col in range(self.cols): + # Start from right edge (for example: total plate width - edge) + x_center = self.plate_width - edge + + # Subtract gauges from right to left + for i in range(col): + x_center -= gauge1 if i % 2 == 0 else gauge2 + + # Y-position stays the same + y_center = end + row * pitch + + # Top-left corner for drawing the circle + x = x_center - hole_diameter / 2 + y = y_center - hole_diameter / 2 + + print(f"row: {row}, col: {col}, x: {x}, y: {y}") + self.scene.addEllipse(x, y, hole_diameter, hole_diameter, outline_pen) + weld_size=self.weldsize + weld_gap=self.weldgap + x_center=self.plate_width/2 + y_center=self.plate_height/2 + self.scene.addRect(x_center-weld_gap/2-weld_size, 0, weld_size, height, dimension_pen,red_brush) + self.scene.addRect(x_center+weld_gap/2, 0, weld_size, height, dimension_pen,red_brush) + print(params,dimension_pen) + # Add dimensions + self.addDimensions(params, dimension_pen) + + def addDimensions(self, params, pen): + # Extract parameters + pitch = params['pitch'] + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + else: + gauge1 = params['gauge1'] + gauge2 = params['gauge2'] + edge = params['edge'] + + if 'gauge' in params: + gauge1 = gauge + gauge2 = gauge + + width = self.plate_width + height = self.plate_height + + # Offsets for dimension lines + h_offset = 20 + v_offset = 30 + + # Add horizontal dimensions + x_start = width + segments = [] + # First edge + segments.append(('edge', x_start-edge, x_start )) + x_start -=edge + + # Last edge + segments.append(('edge', 0, x_start)) + + # Draw each segment + for label, x1, x2 in segments: + value = x2 - x1 + self.addHorizontalDimension(x1, -h_offset, x2, -h_offset, f"{value:.1f}", pen) + # Add vertical dimensions + self.addVerticalDimension(width + v_offset, 0, width + v_offset, end, str(end), pen) + for i in range(self.rows - 1): + self.addVerticalDimension(width + v_offset, end + i * pitch, width + v_offset, end + (i + 1) * pitch, str(pitch), pen) + + # Add bottom end distance dimension + self.addVerticalDimension(width + v_offset, height, width + v_offset, height - end, str(end), pen) + + # Add left side dimension + total_height = 2 * end + (self.rows - 1) * pitch + self.addVerticalDimension(-v_offset, 0, -v_offset, total_height, str(total_height), pen) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) \ No newline at end of file diff --git a/src/osdag/gui/seatedanglespacing.py b/src/osdag/gui/seatedanglespacing.py new file mode 100644 index 000000000..e246c5f78 --- /dev/null +++ b/src/osdag/gui/seatedanglespacing.py @@ -0,0 +1,303 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +class SeatedanglespacingOnCol(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + + self.connection = connection_obj + self.val=rows + + if self.val==3 or self.val==4: + self.plate_width=main.seated_angle.width + self.plate_length=main.seated_angle.leg_a_length + self.plate_thickness=float(main.seated_angle.designation.split(" x ")[-1]) + else: + self.plate_width=main.top_angle.width + self.plate_length=main.top_angle.leg_a_length + self.plate_thickness=float(main.top_angle.designation.split(" x ")[-1]) + + + arr=[main.top_spacing_col(main,True),main.top_spacing_beam(main,True),main.seated_spacing_col(main,True), + main.seated_spacing_beam(main,True)] + val=self.val-1 + print(val) + # print(arr[0],len(arr[0])) + # print('\n\n') + # for i in range(len(arr[0])): + # print(f"INDEX : {i} : {arr[0][i]} , {arr[0][i][3]}") + for i in arr[2]: + print(i) + print('\n\n') + + data = {entry[0]: entry[3] for entry in arr[val] if entry[0]} + print(data) + self.rows = data['Bolt.Rows'] + self.cols = data['Bolt.Cols'] + self.End = data['Bolt.EndDist'] + self.Gauge = data['Bolt.Gauge'] + if self.Gauge==0 and 'Bolt.GaugeCentral' in data: + self.Gauge=data['Bolt.GaugeCentral'] + self.Edge = data['Bolt.EdgeDist'] + # return + print(f""" + Plate Dimensions + ---------------- + Plate Width : {self.plate_width} mm + Plate Length : {self.plate_length} mm + + Bolt Layout + ----------- + Rows : {self.rows} + Columns : {self.cols} + End Distance : {self.End} mm + Gauge : {self.Gauge} mm + Edge Distance: {self.Edge} mm + """) + # self.initUI() + self.param_map = { + 'end': self.End, + 'gauge': self.Gauge, + 'edge': self.Edge, + 'hole': main.bolt.bolt_diameter_provided +} + + print(self.param_map) + self.initUI() + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 1050, 750) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + params=self.param_map + # Parameter display labels + # Display the parameter values + for key, value in params.items(): + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} Distance (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Right panel for the drawing using QGraphicsView + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Create and add the drawing to the scene + self.createDrawing(params) + + # Add panels to main layout + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(self.view, 3) + + # Set main widget + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + # Ensure the view shows all content + self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) + + + + def createDrawing(self, params): + + # Extract parameters + + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + edge = params['edge'] + hole_diameter = params['hole'] + print(f"rows: {self.rows}, cols: {self.cols}") + # Calculate dimensions + + width = self.plate_width + + height = self.plate_length + # Set up pens + outline_pen = QPen(Qt.blue, 2) + dimension_pen = QPen(Qt.black, 1.5) + weld_fill = QBrush(Qt.red) + + # Dimension offsets + h_offset = 40 + v_offset = 60 + + # Create scene rectangle with extra space for dimensions + self.scene.setSceneRect(-h_offset, -v_offset, + width + 2*v_offset, height + 2*h_offset) + + # Draw rectangle + self.scene.addRect(0, 0, width, height, dimension_pen) + + if self.val==3 or self.val==1: + self.scene.addRect(0, height-self.plate_thickness, width, self.plate_thickness, dimension_pen, weld_fill) + elif self.val==4 or self.val==2: + self.scene.addRect(0, 0, width, self.plate_thickness, dimension_pen, weld_fill) + + + # Draw holes + for row in range(self.rows): + for col in range(self.cols): + # Start from edge distance (center of first hole) + x_center = edge + for i in range(col): + x_center += gauge + + # Center of hole is at (x_center, y_center) + # Subtract hole_diameter/2 to draw ellipse properly from top-left + x = x_center - hole_diameter / 2 + y_center = end + y = y_center - hole_diameter / 2 + + print(f"row: {row}, col: {col}, x: {x}, y: {y}") + self.scene.addEllipse(x, y, hole_diameter, hole_diameter, outline_pen) + print(params,dimension_pen) + # Add dimensions + self.addDimensions(params, dimension_pen) + + def addDimensions(self, params, pen): + # Extract parameters + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + + edge = params['edge'] + + + + width=self.plate_width + height=self.plate_length + + # Offsets for dimension lines + h_offset = 20 + v_offset = 30 + + # Add horizontal dimensions + x_start = 0 + segments = [] + # First edge + segments.append(('edge', x_start, x_start + edge)) + x_start += edge + segments.append(('edge' ,x_start,x_start+gauge )) + x_start+=gauge + # Last edge + segments.append(('edge', x_start, x_start + edge)) + + # Draw each segment + for label, x1, x2 in segments: + value = x2 - x1 + self.addHorizontalDimension(x1, -h_offset, x2, -h_offset, f"{value:.1f}", pen) + self.addHorizontalDimension(0,height+h_offset,width,height+h_offset,f"{width} mm" , pen) + # Add vertical dimensions + # Add top end distance dimension (from 0 to end) + self.addVerticalDimension(width + v_offset, 0, width + v_offset, end, str(end), pen) + + # Add remaining distance from end to height + self.addVerticalDimension(width + v_offset , end, width + v_offset , height, str(height - end), pen) + + # Add left side dimension + total_height = 2 * end + (self.rows - 1) + self.addVerticalDimension(-v_offset/2, 0, -v_offset/2, height, str(height), pen) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) \ No newline at end of file diff --git a/src/osdag/gui/spacing.py b/src/osdag/gui/spacing.py new file mode 100644 index 000000000..2290b04a1 --- /dev/null +++ b/src/osdag/gui/spacing.py @@ -0,0 +1,297 @@ +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QGraphicsView, + QGraphicsScene) +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import Qt, QRectF +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtGui import QPolygonF, QBrush +from PyQt5.QtCore import QPointF +from ..Common import * +from .additionalfns import calculate_total_width +from ..design_type.connection.end_plate_connection import EndPlateConnection + +class BoltPatternGenerator(QMainWindow): + def __init__(self, connection_obj, rows=3, cols=2 , main = None): + super().__init__() + self.connection = connection_obj + self.main=main + self.plate_height = main.plate.height + self.plate_width = main.plate.length + self.hole_dia=main.bolt.bolt_diameter_provided + self.rows=main.plate.bolts_one_line + self.cols=main.plate.bolt_line + print(self.plate_height,self.plate_width) + output=main.output_values(main,True) + dict1={i[0] : i[3] for i in output} + for i in output: + print(i) + self.weldsize=0 + if 'Weld.Size' in dict1: + self.weldsize=dict1['Weld.Size'] + self.initUI() + # print(self.connection.spacing(status=True)) + def initUI(self): + self.setWindowTitle('Bolt Pattern Generator') + self.setGeometry(100, 100, 800, 500) + + # Main layout + main_layout = QHBoxLayout() + + # Left panel for parameter display + left_panel = QWidget() + left_layout = QVBoxLayout() + + # Parameter display labels + params = self.get_parameters() + + # Display the parameter values + for key, value in params.items(): + param_layout = QHBoxLayout() + param_label = QLabel(f'{key.title()} Distance (mm):') + value_label = QLabel(f'{value}') + param_layout.addWidget(param_label) + param_layout.addWidget(value_label) + left_layout.addLayout(param_layout) + + left_layout.addStretch() + left_panel.setLayout(left_layout) + + # Right panel for the drawing using QGraphicsView + self.scene = QGraphicsScene() + self.view = QGraphicsView(self.scene) + self.view.setRenderHint(QPainter.Antialiasing) + + # Create and add the drawing to the scene + self.createDrawing(params) + + # Add panels to main layout + main_layout.addWidget(left_panel, 1) + main_layout.addWidget(self.view, 3) + + # Set main widget + main_widget = QWidget() + main_widget.setLayout(main_layout) + self.setCentralWidget(main_widget) + + # Ensure the view shows all content + self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) + def get_parameters(self): + spacing_data = self.connection.spacing(status=True) # Get actual values + param_map = {} + print('spacing_data length' , len(spacing_data)) + for item in spacing_data: + key, _, _, value = item + # print('key : ', key) + if key == KEY_OUT_PITCH: + param_map['pitch'] = float(value) + elif key == KEY_OUT_END_DIST: + param_map['end'] = float(value) + elif key == KEY_OUT_GAUGE1: + param_map['gauge1'] = float(value) + elif key == KEY_OUT_GAUGE2: + param_map['gauge2'] = float(value) + elif key == KEY_OUT_GAUGE: + param_map['gauge'] = float(value) + elif key == KEY_OUT_EDGE_DIST: + param_map['edge'] = float(value) + + # Add hardcoded hole diameter + param_map['hole'] = self.main.bolt.bolt_diameter_provided + + print("Extracted parameters:", param_map) + + return param_map + + def createDrawing(self, params): + + # Extract parameters + pitch = params['pitch'] + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + else: + gauge1 = params['gauge1'] + gauge2 = params['gauge2'] + edge = params['edge'] + hole_diameter = params['hole'] + + # Calculate dimensions + if 'gauge' in params: + gauge1 = gauge + gauge2 = gauge + width = self.plate_width + + height = self.plate_height + + # Set up pens + outline_pen = QPen(Qt.blue, 2) + dimension_pen = QPen(Qt.black, 1.5) + red_brush = QBrush(Qt.red) + + # Dimension offsets + h_offset = 40 + v_offset = 60 + + # Create scene rectangle with extra space for dimensions + self.scene.setSceneRect(-h_offset, -v_offset, + width + 2*v_offset, height + 2*h_offset) + + # Draw rectangle + self.scene.addRect(0, 0, width, height, dimension_pen) + + # Draw holes + for row in range(self.rows): + for col in range(self.cols): + # Start from right edge (for example: total plate width - edge) + x_center = self.plate_width - edge + + # Subtract gauges from right to left + for i in range(col): + x_center -= gauge1 if i % 2 == 0 else gauge2 + + # Y-position stays the same + y_center = end + row * pitch + + # Top-left corner for drawing the circle + x = x_center - hole_diameter / 2 + y = y_center - hole_diameter / 2 + + print(f"row: {row}, col: {col}, x: {x}, y: {y}") + self.scene.addEllipse(x, y, hole_diameter, hole_diameter, outline_pen) + weld_size=self.weldsize + self.scene.addRect(0, 0, weld_size, height, dimension_pen,red_brush) + print(params,dimension_pen) + # Add dimensions + self.addDimensions(params, dimension_pen) + + def addDimensions(self, params, pen): + # Extract parameters + pitch = params['pitch'] + end = params['end'] + if 'gauge' in params: + gauge = params['gauge'] + else: + gauge1 = params['gauge1'] + gauge2 = params['gauge2'] + edge = params['edge'] + + if 'gauge' in params: + gauge1 = gauge + gauge2 = gauge + + width = self.plate_width + height = self.plate_height + + # Offsets for dimension lines + h_offset = 20 + v_offset = 30 + + # Add horizontal dimensions + x_start = width + segments = [] + # First edge + segments.append(('edge', x_start-edge, x_start )) + x_start -=edge + + # Last edge + segments.append(('edge', 0, x_start)) + + # Draw each segment + for label, x1, x2 in segments: + value = x2 - x1 + self.addHorizontalDimension(x1, -h_offset, x2, -h_offset, f"{value:.1f}", pen) + # Add vertical dimensions + self.addVerticalDimension(width + v_offset, 0, width + v_offset, end, str(end), pen) + for i in range(self.rows - 1): + self.addVerticalDimension(width + v_offset, end + i * pitch, width + v_offset, end + (i + 1) * pitch, str(pitch), pen) + + # Add bottom end distance dimension + self.addVerticalDimension(width + v_offset, height, width + v_offset, height - end, str(end), pen) + + # Add left side dimension + total_height = 2 * end + (self.rows - 1) * pitch + self.addVerticalDimension(-v_offset, 0, -v_offset, total_height, str(total_height), pen) + + def addHorizontalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1, y1 - ext_length/2, x1, y1 + ext_length/2, pen) + self.scene.addLine(x2, y2 - ext_length/2, x2, y2 + ext_length/2, pen) + + points_left = [ + (x1, y1), + (x1 + arrow_size, y1 - arrow_size/2), + (x1 + arrow_size, y1 + arrow_size/2) + ] + polygon_left = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_left]), pen) + polygon_left.setBrush(QBrush(Qt.black)) + + points_right = [ + (x2, y2), + (x2 - arrow_size, y2 - arrow_size/2), + (x2 - arrow_size, y2 + arrow_size/2) + ] + polygon_right = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_right]), pen) + polygon_right.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if y1 < 0: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 - 25) + else: + text_item.setPos((x1 + x2) / 2 - text_item.boundingRect().width() / 2, y1 + 5) + + def addVerticalDimension(self, x1, y1, x2, y2, text, pen): + self.scene.addLine(x1, y1, x2, y2, pen) + arrow_size = 5 + ext_length = 10 + self.scene.addLine(x1 - ext_length/2, y1, x1 + ext_length/2, y1, pen) + self.scene.addLine(x2 - ext_length/2, y2, x2 + ext_length/2, y2, pen) + + if y2 > y1: + points_top = [ + (x1, y1), + (x1 - arrow_size/2, y1 + arrow_size), + (x1 + arrow_size/2, y1 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x2, y2), + (x2 - arrow_size/2, y2 - arrow_size), + (x2 + arrow_size/2, y2 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + else: + points_top = [ + (x2, y2), + (x2 - arrow_size/2, y2 + arrow_size), + (x2 + arrow_size/2, y2 + arrow_size) + ] + polygon_top = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_top]), pen) + polygon_top.setBrush(QBrush(Qt.black)) + + points_bottom = [ + (x1, y1), + (x1 - arrow_size/2, y1 - arrow_size), + (x1 + arrow_size/2, y1 - arrow_size) + ] + polygon_bottom = self.scene.addPolygon(QPolygonF([QPointF(x, y) for x, y in points_bottom]), pen) + polygon_bottom.setBrush(QBrush(Qt.black)) + + text_item = self.scene.addText(text) + font = QFont() + font.setPointSize(5) + text_item.setFont(font) + + if x1 < 0: + text_item.setPos(x1 - 10 - text_item.boundingRect().width(), (y1 + y2) / 2 - text_item.boundingRect().height() / 2) + else: + text_item.setPos(x1 + 15, (y1 + y2) / 2 - text_item.boundingRect().height() / 2) \ No newline at end of file diff --git a/src/osdag/gui/ui_aboutosdag.py b/src/osdag/gui/ui_aboutosdag.py index 77b660425..5f9d2dc2f 100644 --- a/src/osdag/gui/ui_aboutosdag.py +++ b/src/osdag/gui/ui_aboutosdag.py @@ -7,6 +7,7 @@ # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets +from .._version import __version__ class Ui_AboutOsdag(object): def setupUi(self, Dialog): @@ -35,7 +36,7 @@ def retranslateUi(self, Dialog): "p, li { white-space: pre-wrap; }\n" "\n" "

Osdag©

\n" -"

Version: 2021.02.a.a12f

\n" +f"

Version: {__version__}

\n" "


\n" "

Osdag is a cross-platform, free, and open-source software for the design and detailing of steel structures, following the Indian Standard IS 800:2007. Osdag is primarily built using Python other Python-based FOSS tools, such as, PyQt, OpenCascade, PythonOCC, SQLite. It allows the user to design steel connections, members and systems using a graphical user interface. The interactive GUI provides a 3D visualisation of the designed component and an option to export the CAD model to any drafting software for the creation of construction/fabrication drawings. The design is typically optimised following industry best practices. Osdag is developed by the Osdag team at IIT Bombay under the initiative of FOSSEE funded by the Ministry of Education (MoE), Government of India.

\n" "


\n" diff --git a/src/osdag/gui/ui_template.py b/src/osdag/gui/ui_template.py index c112b739e..0f94cd282 100644 --- a/src/osdag/gui/ui_template.py +++ b/src/osdag/gui/ui_template.py @@ -3,6 +3,8 @@ import shutil import time import pandas as pd +import subprocess +import sys from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtGui import * from PyQt5.QtWidgets import * @@ -19,7 +21,9 @@ from .customized_popup import Ui_Popup # from .ui_summary_popup import Ui_Dialog1 #from .ui_design_preferences import Ui_Dialog - +from .beam2beamcoverplatedetailing import B2Bcoverplate +from .b2cendplateSketch import B2BEndPlateSketch +from .beam2beamcoverplatedetailing_capacity_details import B2Bcoverplate_capacity_details from .ui_summary_popup import Ui_Dialog1 from ..design_report.reportGenerator import save_html from .ui_OsdagSectionModeller import Ui_OsdagSectionModeller @@ -54,19 +58,30 @@ from ..design_type.flexural_member.flexure import Flexure from ..design_type.flexural_member.flexure_cantilever import Flexure_Cantilever from ..design_type.flexural_member.flexure_othersupp import Flexure_Misc +from ..design_type.flexural_member.flexure_purlin import Flexure_Purlin from ..gusset_connection import GussetConnection import logging import subprocess from ..get_DPI_scale import scale,height,width from ..cad.cad3dconnection import cadconnection from pynput.mouse import Button, Controller - +from osdag.gui.spacing import BoltPatternGenerator +from osdag.gui.capacity_details_finPlate import CapacityDetailsWindow +from .seatedanglespacing import SeatedanglespacingOnCol +from .Beam2ColEnddetailing import BeamtoColDetailing +from .baseplatedetailing import BasePlateDetailing +from .baseplatedetailinghollow import BasePlateDetailingHollow +from .b2bcoverplateweld import B2Bcoverplateweld + +from .cleatangledetailing import CleatAngle +from .BC2Cendplate import BC2CEndPlate +from .endplatecnndetailnig import EndPlateDetailer class MyTutorials(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self.ui = Ui_Tutorial() self.ui.setupUi(self) - + self.active_dialog = None class MyAboutOsdag(QDialog): def __init__(self, parent=None): @@ -865,7 +880,6 @@ def setupUi(self, MainWindow, main,folder): else: for t in updated_list: for key_name in t[0]: - key_changed = self.dockWidgetContents.findChild(QtWidgets.QWidget, key_name) self.on_change_connect(key_changed, updated_list, data, main) print(f"key_name{key_name} \n key_changed{key_changed} \n self.on_change_connect ") @@ -1866,6 +1880,8 @@ def return_class(self,name): return Flexure_Cantilever elif name == KEY_DISP_FLEXURE3: return Flexure_Misc + elif name == KEY_DISP_FLEXURE4: + return Flexure_Purlin else: return GussetConnection # Function for getting inputs from a file @@ -2105,7 +2121,7 @@ def common_function_for_save_and_design(self, main, data, trigger_type): KEY_DISP_ENDPLATE, KEY_DISP_BASE_PLATE, KEY_DISP_SEATED_ANGLE, KEY_DISP_TENSION_BOLTED, KEY_DISP_TENSION_WELDED, KEY_DISP_COLUMNCOVERPLATE, KEY_DISP_COLUMNCOVERPLATEWELD, KEY_DISP_COLUMNENDPLATE, KEY_DISP_BCENDPLATE, KEY_DISP_BB_EP_SPLICE, - KEY_DISP_COMPRESSION_COLUMN,KEY_DISP_FLEXURE,KEY_DISP_FLEXURE2,KEY_DISP_COMPRESSION_Strut]: # , KEY_DISP_FLEXURE + KEY_DISP_COMPRESSION_COLUMN,KEY_DISP_FLEXURE,KEY_DISP_FLEXURE2,KEY_DISP_FLEXURE3,KEY_DISP_FLEXURE4,KEY_DISP_COMPRESSION_Strut]: # , KEY_DISP_FLEXURE # print(self.display, self.folder, main.module, main.mainmodule) print("common start") print(f"main object type: {type(main)}") @@ -2113,7 +2129,7 @@ def common_function_for_save_and_design(self, main, data, trigger_type): print("main.mainmodule",main.mainmodule) self.commLogicObj = CommonDesignLogic(self.display, self.folder, main.module, main.mainmodule) - print(main.module) + print(f"This is MAIN.MODULE {main.module}") print(main.mainmodule) # print("common start") status = main.design_status @@ -2134,24 +2150,7 @@ def common_function_for_save_and_design(self, main, data, trigger_type): action.setEnabled(True) fName = str('./ResourceFiles/images/3d.png') file_extension = fName.split(".")[-1] - - # if file_extension == 'png': - # self.display.ExportToImage(fName) - # im = Image.open('./ResourceFiles/images/3d.png') - # w,h=im.size - # if(w< 640 or h < 360): - # print('Re-taking Screenshot') - # self.resize(700,500) - # self.outputDock.hide() - # self.inputDock.hide() - # self.textEdit.hide() - # QTimer.singleShot(0, lambda:self.retakeScreenshot(fName)) - else: - for fName in ['3d.png', 'top.png', - 'front.png', 'side.png']: - with open("./ResourceFiles/images/"+fName, 'w'): - pass self.display.EraseAll() for chkbox in main.get_3d_components(main): self.frame.findChild(QtWidgets.QCheckBox, chkbox[0]).setEnabled(False) @@ -2192,7 +2191,30 @@ def osdag_header(self): def output_button_connect(self, main, button_list, b): b.clicked.connect(lambda: self.output_button_dialog(main, button_list, b)) + def run_spacing_script(self,cols,rows,generator_class=BoltPatternGenerator , main=None): + print("Creating spacing window...") + self.spacing_window = generator_class(self.Obj,cols=cols,rows=rows,main=main) + self.spacing_window.setWindowTitle("Spacing Viewer") + self.spacing_window.raise_() + self.spacing_window.activateWindow() + self.spacing_window.show() + + def run_capacity_details(self,cols,rows,generator_class=CapacityDetailsWindow , main=None): + print("Creating capacity details window...") + print("++++++++++++++++++++++++++++++DEBUG++++++++++++++++++++++++++++++") + print(generator_class) + print("++++++++++++++++++++++++++++++DEBUG++++++++++++++++++++++++++++++") + self.capacity_window = generator_class(self.Obj,cols=cols,rows=rows,main=main) + self.capacity_window.setWindowTitle("Capacity Details") + self.capacity_window.raise_() + self.capacity_window.activateWindow() + self.capacity_window.show() + + + + def output_button_dialog(self, main, button_list, button): + import inspect dialog = QtWidgets.QDialog() dialog.setObjectName("Dialog") @@ -2231,12 +2253,168 @@ def output_button_dialog(self, main, button_list, button): section = 0 no_note = True - for op in button_list: + for op in button_list: + if op[0] == button.objectName(): + print(op) + print("DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG") + print(main) + print("DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG_DEBUG") tup = op[3] title = tup[0] fn = tup[1] + cls = fn.__qualname__.split('.')[0] + if op[0] == 'spacing' or op[0]=='Cleat.Spting_leg.spacing': + # print(main) + self.active_dialog = QtWidgets.QDialog() + dialog = self.active_dialog + module = inspect.getmodule(fn) # Get the module where the function is defined + cls_obj = getattr(module, cls) # Get the actual class object + self.Obj = cls_obj() + if main is FinPlateConnection: + if hasattr(self.Obj, 'spting_leg') and \ + hasattr(self.Obj.spting_leg, 'bolt_line') and \ + hasattr(self.Obj.spting_leg, 'bolts_one_line'): + self.run_spacing_script(self.Obj.spting_leg.bolts_one_line,self.Obj.spting_leg.bolt_line, + main=main) + else: + self.run_spacing_script(rows=self.Obj.plate.bolts_one_line,cols=self.Obj.plate.bolt_line, + main=main) + elif main is CleatAngleConnection and op[0]=='spacing': + self.run_spacing_script(0,0,CleatAngle,(main,0)) + elif op[0]!='spacing' and main is CleatAngleConnection: + self.run_spacing_script(0,0,CleatAngle,(main,1)) + elif main is EndPlateConnection: + self.run_spacing_script(0,0,EndPlateDetailer,main) + # return + # Instantiate it + + break + + elif ((op[0]=='button1' or op[0]=='button2') and op[3][0]=='Capacity Details' and main is FinPlateConnection) : + self.active_dialog = QtWidgets.QDialog() + dialog = self.active_dialog + module = inspect.getmodule(fn) # Get the module where the function is defined + cls_obj = getattr(module, cls) # Get the actual class object + self.Obj = cls_obj() + if main is FinPlateConnection: + if hasattr(self.Obj, 'spting_leg') and \ + hasattr(self.Obj.spting_leg, 'bolt_line') and \ + hasattr(self.Obj.spting_leg, 'bolts_one_line'): + self.run_capacity_details(self.Obj.spting_leg.bolts_one_line,self.Obj.spting_leg.bolt_line, + main=main) + else: + self.run_capacity_details(rows=self.Obj.plate.bolts_one_line,cols=self.Obj.plate.bolt_line, + main=main) + break + + + elif op[0].startswith('SeatedAngle') or op[0].startswith('TopAngle'): + + module = inspect.getmodule(fn) # Get the module where the function is defined + cls_obj = getattr(module, cls) # Get the actual class object + self.Obj = cls_obj() # Instantiate it + if op[0]=='SeatedAngle.Bolt_Spacing_col': + val=3 + elif op[0]=='SeatedAngle.Bolt_Spacing_beam': + val=4 + elif op[0]=='TopAngle.Bolt_Spacing_col': + val=1 + else: + val=2 + self.run_spacing_script(None, + val,#specifying which to use + SeatedanglespacingOnCol,main) + return + print(KEY_OUT_ROW_PROVIDED , KEY_OUT_COL_PROVIDED) + elif op[0]=='Detailing' and op[1]=='Typical Detailing': + + module = inspect.getmodule(fn) # Get the module where the function is defined + cls_obj = getattr(module, cls) # Get the actual class object + self.Obj = cls_obj() + print(f'rows: {self.Obj.bolt_row} , cols : {self.Obj.bolt_column} , {self.Obj.bolt_row_web}') + self.run_spacing_script(0,0,BeamtoColDetailing,main) + data=main.output_values(main,True) + return + elif op[0]=='BasePlate.Detailing': + + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + if main.connectivity == 'Moment Base Plate' or main.connectivity=='Welded Column Base': + self.run_spacing_script(0,0,BasePlateDetailing,main) + else: + self.run_spacing_script(0,0,BasePlateDetailingHollow,main) + return + elif op[0]=='Web_plate.spacing': + + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + + self.run_capacity_details(0,0,B2Bcoverplate,(main,True, "spacing")) + return + elif op[0]=='Flange_plate.spacing': + + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + + self.run_capacity_details(0,0,B2Bcoverplate,(main,False, "spacing")) + return + elif op[0]=='Web detail' and main is BeamCoverPlateWeld: + + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + + self.run_spacing_script(0,0,B2Bcoverplateweld,(main,True)) + return + elif op[0]=='Flange detail' and main is BeamCoverPlateWeld: + + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + + self.run_spacing_script(0,0,B2Bcoverplateweld,(main,False)) + return + + + #im working here + elif op[0]=='section.web_capacities' and main is BeamCoverPlate: + + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + self.run_capacity_details(0,0,B2Bcoverplate_capacity_details,(main,True,"capacity")) + return + + #im working here + elif op[0]=='section.flange_capacity' and main is BeamCoverPlate: + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + self.run_capacity_details(0,0,B2Bcoverplate_capacity_details,(main,False,"capacity")) + return + + #im working here + elif op[0]=="Stiffener.Sketch" and op[1]=="Typical Sketch": + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + self.run_spacing_script(0,0,B2BEndPlateSketch,main) + return + + elif op[0]=='Bolt.web_bolts' or op[0]=='Bolt.flange_bolts': + module=inspect.getmodule(fn) + cls_obj=getattr(module,cls) + self.Obj=cls_obj() + if op[0]=='Bolt.web_bolts': + self.run_spacing_script(0,0,BC2CEndPlate,(main,0)) + else: + self.run_spacing_script(0,0,BC2CEndPlate,(main,1)) + break dialog.setWindowTitle(title) j = 1 _translate = QtCore.QCoreApplication.translate diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py index d49647a3b..13736a794 100644 --- a/src/osdag/osdagMainPage.py +++ b/src/osdag/osdagMainPage.py @@ -166,6 +166,7 @@ from .design_type.flexural_member.flexure import Flexure from .design_type.flexural_member.flexure_cantilever import Flexure_Cantilever +from .design_type.flexural_member.flexure_purlin import Flexure_Purlin from .design_type.flexural_member.flexure_othersupp import Flexure_Misc # from .design_type.plate_girder.weldedPlateGirder import PlateGirderWelded # from .cad.cad_common import call_3DBeam @@ -312,22 +313,21 @@ def __init__(self): 'Flexural Member' : [ ('Simply Supported Beam', str(files("osdag.data.ResourceFiles.images").joinpath("simply-supported-beam.jpg")), 'Beam_flexure'), ('Cantilever Beam', str(files("osdag.data.ResourceFiles.images").joinpath("cantilever-beam.jpg")), 'Beam_flexure2'), + ('Purlin', str(files("osdag.data.ResourceFiles.images").joinpath("purlin.jpg")), 'Beam_flexure4'), # ('Other Beams', str(files("osdag.data.ResourceFiles.images").joinpath("fixed-beam.png")), 'Beam_flexure3'), - # ('Laterally Unsupported Beam', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Truss_Welded'), self.show_flexure_module, ], 'Beam-Column' : self.Under_Development, - 'Plate Girder' : self.Under_Development, # TODO @rutvik # 'Beam-Column' :[ # ('Beam-Column Design', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Beam_Column_Design'), # self.show_beamcolumn_module, # ], - # 'Plate Girder' : [ #TODO: Check number of sub modules required - # ('Welded Girder Design', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Welded_Girder_Design'), - # self.Show_Girder_Design, - # ], + 'Plate Girder' : [ #TODO: Check number of sub modules required + ('Simply Supported', str(files('osdag.data.ResourceFiles.images').joinpath('simply-supported-beam.jpg')), 'Welded_Girder_Design'), + self.show_girder_design, + ], 'Truss' : self.Under_Development, '2D Frame' : self.Under_Development, '3D Frame' : self.Under_Development, @@ -533,96 +533,95 @@ def ButtonConnection(self,Button,Modules,ModuleName): @pyqtSlot() def show_shear_connection(self): - if self.findChild(QRadioButton,'Fin_Plate').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(FinPlateConnection, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton,'Cleat_Angle').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(CleatAngleConnection, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton,'Seated_Angle').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow( SeatedAngleConnection, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton,'End_Plate').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(EndPlateConnection, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - else: - QMessageBox.about(self, "INFO", "Please select appropriate connection") + button_name_window_type_pairs = \ + [("Fin_Plate", FinPlateConnection), + ("Cleat_Angle", CleatAngleConnection), + ("Seated_Angle", SeatedAngleConnection), + ("End_Plate", EndPlateConnection),] + + for (button_name, window_type) in button_name_window_type_pairs: + btn = self.findChild(QRadioButton, button_name) + if btn is not None and btn.isChecked(): + self.hide() + self.ui2 = Ui_ModuleWindow(window_type, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate connection") def show_moment_connection(self): - if self.findChild(QRadioButton,'B2B_Cover_Plate_Bolted').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(BeamCoverPlate, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton,'B2B_Cover_Plate_Welded').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(BeamCoverPlateWeld, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - # elif self.findChild(QRadioButton,'B2B_End_Plate_Connection').isChecked(): - # self.hide() - # self.ui2 = Ui_ModuleWindow(BeamBeamEndPlateSplice,' ') - # self.ui2.show() - # self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton, 'B2B_End_Plate_Splice').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(BeamBeamEndPlateSplice, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) + button_name_window_type_pairs = \ + [("B2B_Cover_Plate_Bolted", BeamCoverPlate), + ("B2B_Cover_Plate_Welded", BeamCoverPlateWeld), + # ("B2B_End_Plate_Connection", BeamBeamEndPlateSplice), + ("B2B_End_Plate_Splice", BeamBeamEndPlateSplice),] + + for (button_name, window_type) in button_name_window_type_pairs: + btn = self.findChild(QRadioButton, button_name) + if btn is not None and btn.isChecked(): + self.hide() + self.ui2 = Ui_ModuleWindow(window_type, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate connection") def show_moment_connection_bc(self): - if self.findChild(QRadioButton,'BC_End_Plate').isChecked(): + btn = self.findChild(QRadioButton, "BC_End_Plate") + if btn is not None and btn.isChecked(): self.hide() self.ui2 = Ui_ModuleWindow(BeamColumnEndPlate, ' ') self.ui2.show() self.ui2.closed.connect(self.show) + else: + QMessageBox.about(self, "INFO", "Please select appropriate connection") def show_base_plate(self): - if self.findChild(QRadioButton, 'Base_Plate').isChecked(): + btn = self.findChild(QRadioButton, "Base_Plate") + if btn is not None and btn.isChecked(): self.hide() self.ui2 = Ui_ModuleWindow(BasePlateConnection, ' ') self.ui2.show() self.ui2.closed.connect(self.show) - - def show_truss_bolted(self): - if self.findChild(QRadioButton, 'Truss_Bolted').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(TrussConnectionBolted, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - #elif self.findChild(QRadioButton,'Truss_Welded').isChecked(): - # self.hide() - # self.ui2 = Ui_ModuleWindow(BasePlateConnection, ' ') - # self.ui2.show() - # self.ui2.closed.connect(self.show) else: QMessageBox.about(self, "INFO", "Please select appropriate connection") - def show_moment_connection_cc(self): - if self.findChild(QRadioButton,'C2C_Cover_Plate_Bolted').isChecked() : - self.hide() - self.ui2 = Ui_ModuleWindow(ColumnCoverPlate, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton,'C2C_Cover_Plate_Welded').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(ColumnCoverPlateWeld, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) + def show_truss_bolted(self): + button_name_window_type_pairs = \ + [ + ("Truss_Bolted", TrussConnectionBolted), + # ("Truss_Welded", BasePlateConnection), + ] + + for (button_name, window_type) in button_name_window_type_pairs: + btn = self.findChild(QRadioButton, button_name) + if btn is not None and btn.isChecked(): + self.hide() + self.ui2 = Ui_ModuleWindow(window_type, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate connection") - elif self.findChild(QRadioButton,'C2C_End_Plate_Connection').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(ColumnEndPlate, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) + def show_moment_connection_cc(self): + button_name_window_type_pairs = \ + [("C2C_Cover_Plate_Bolted", ColumnCoverPlate), + ("C2C_Cover_Plate_Welded", ColumnCoverPlateWeld), + ("C2C_End_Plate_Connection", ColumnEndPlate),] + + for (button_name, window_type) in button_name_window_type_pairs: + btn = self.findChild(QRadioButton, button_name) + if btn is not None and btn.isChecked(): + self.hide() + self.ui2 = Ui_ModuleWindow(window_type, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate connection") # def show_compression_module(self): # # folder = self.select_workspace_folder() @@ -659,93 +658,73 @@ def show_moment_connection_cc(self): # self.ui2.closed.connect(self.show) def show_tension_module(self): - # folder = self.select_workspace_folder() - # folder = str(folder) - # if not os.path.exists(folder): - # if folder == '': - # pass - # else: - # os.mkdir(folder, 0o755) - # - # root_path = folder - # images_html_folder = ['images_html'] - # flag = True - # for create_folder in images_html_folder: - # if root_path == '': - # flag = False - # return flag - # else: - # try: - # os.mkdir(os.path.join(root_path, create_folder)) - # except OSError: - # shutil.rmtree(os.path.join(folder, create_folder)) - # os.mkdir(os.path.join(root_path, create_folder)) - - if self.findChild(QRadioButton,'Tension_Bolted').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(Tension_bolted, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) + button_name_window_type_pairs = \ + [("Tension_Bolted", Tension_bolted), + ("Tension_Welded", Tension_welded),] - elif self.findChild(QRadioButton,'Tension_Welded').isChecked(): - self.hide() - self.ui2 = Ui_ModuleWindow(Tension_welded, ' ') - self.ui2.show() - self.ui2.closed.connect(self.show) + for (button_name, window_type) in button_name_window_type_pairs: + btn = self.findChild(QRadioButton, button_name) + if btn is not None and btn.isChecked(): + self.hide() + self.ui2 = Ui_ModuleWindow(window_type, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate tension module") def show_compression_module(self): """ Create radio buttons for the sub-modules under the compression module""" - # print(f"Here8") - if self.findChild(QRadioButton, 'Column_Design').isChecked(): - # print(f"Here9") + column_design_button = self.findChild(QRadioButton, 'Column_Design') + if column_design_button is not None and column_design_button.isChecked(): self.hide() self.ui2 = Ui_ModuleWindow(ColumnDesign, ' ') - # print(f"Here11") self.ui2.show() self.ui2.closed.connect(self.show) + return - elif self.findChild(QRadioButton, 'Strut_Design').isChecked(): - print(f"Here9") + strut_design_button = self.findChild(QRadioButton, 'Strut_Design') + if strut_design_button is not None and strut_design_button.isChecked(): self.hide() self.ui2 = Ui_ModuleWindow(Compression, ' ') - print(f"Here11.2") self.ui2.show() self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate compression module") def show_flexure_module(self): """ Create radio buttons for the sub-modules under the compression module""" - # print(f"Here8") - if self.findChild(QRadioButton, 'Beam_flexure').isChecked(): - # print(f"Here9") - self.hide() - self.ui2 = Ui_ModuleWindow(Flexure, ' ') - # print(f"Here11") - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton, 'Beam_flexure2').isChecked(): - # print(f"Here9") - self.hide() - self.ui2 = Ui_ModuleWindow(Flexure_Cantilever, ' ') - # print(f"Here11") - self.ui2.show() - self.ui2.closed.connect(self.show) - elif self.findChild(QRadioButton, 'Beam_flexure3').isChecked(): - # print(f"Here9") - self.hide() - self.ui2 = Ui_ModuleWindow(Flexure_Misc, ' ') - # print(f"Here11") - self.ui2.show() - self.ui2.closed.connect(self.show) + + button_name_window_type_pairs = \ + [("Beam_flexure", Flexure), + ("Beam_flexure2", Flexure_Cantilever), + ("Beam_flexure3", Flexure_Misc), + ("Beam_flexure4", Flexure_Purlin)] + + for (button_name, window_type) in button_name_window_type_pairs: + btn = self.findChild(QRadioButton, button_name) + if btn is not None and btn.isChecked(): + self.hide() + self.ui2 = Ui_ModuleWindow(window_type, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + return + + QMessageBox.about(self, "INFO", "Please select appropriate flexure module") + def show_beamcolumn_module(self): - if self.findChild(QRadioButton, 'Beam_flexure').isChecked(): - # print(f"Here9") + btn = self.findChild(QRadioButton, "Beam_flexure") + if btn is not None and btn.isChecked(): self.hide() self.ui2 = Ui_ModuleWindow(Flexure, ' ') - # print(f"Here11") self.ui2.show() self.ui2.closed.connect(self.show) - def Show_Girder_Design(self): - if self.findChild(QRadioButton, 'Welded_Girder_Design').isChecked(): + return + + def show_girder_design(self): + btn = self.findChild(QRadioButton, "Welded_Girder_Design") + if btn is not None and btn.isChecked(): self.hide() self.ui2 = Ui_ModuleWindow(PlateGirderWelded, ' ') self.ui2.show() @@ -775,7 +754,7 @@ def open_question(self): self.ask_question() def design_examples(self): - root_path = os.path.join('ResourceFiles', 'html_page', '_build', 'html') + root_path = files('osdag.data.ResourceFiles.html_page._build').joinpath('html') for html_file in os.listdir(root_path): # if html_file.startswith('index'): print(os.path.splitext(html_file)[1]) @@ -969,5 +948,49 @@ def do_stuff(): except BaseException as e: print("ERROR", e) + +import cProfile +import pstats +import threading +import keyboard # Install with `pip install keyboard` + +profiler = cProfile.Profile() + +def start_profiling(): + print("Profiling started...") + profiler.enable() + +def stop_profiling(): + print("Profiling stopped...") + profiler.disable() + profiler.dump_stats("profile_output") + + stats = pstats.Stats("profile_output") + stats.sort_stats("time") + + # Print to console + stats.print_stats(50) + + # Save output to a text file + with open("profile_output.txt", "w") as f: + stats.stream = f + stats.print_stats(50) + + print("Profile output saved to profile_output.txt") + + +# Run profiling triggers in a separate thread to avoid blocking Osdag +def listen_for_keys(): + keyboard.add_hotkey('p', start_profiling) # Press 'p' to start + keyboard.add_hotkey('s', stop_profiling) # Press 's' to stop + keyboard.wait('esc') # Keep listening until 'esc' is pressed + +# Start the keyboard listener in the background +threading.Thread(target=listen_for_keys, daemon=True).start() + +def main(): + while True: + do_stuff() # Your main Osdag loop + if __name__ == '__main__': - do_stuff() + main() diff --git a/src/osdag/print_trace_wrapper.py b/src/osdag/print_trace_wrapper.py new file mode 100644 index 000000000..f6f577fc2 --- /dev/null +++ b/src/osdag/print_trace_wrapper.py @@ -0,0 +1,49 @@ +import sys +import os +import builtins + +# File to save the trace output +TRACE_OUTPUT_FILE = "trace_output.txt" + +# Path to ignore (conda environment directory) +CONDA_PATH = os.getenv('CONDA_PREFIX', '') # Automatically gets the current conda environment path + +# Backup original print function +original_print = builtins.print + +def traced_print(*args, **kwargs): + # Get the current frame + frame = sys._getframe(1) + function_name = frame.f_code.co_name + line_number = frame.f_lineno + file_path = frame.f_globals.get("__file__", "") + + # Ignore printing from files in the conda environment + if CONDA_PATH and file_path.startswith(CONDA_PATH): + original_print(*args, **kwargs) + return + + # Log the print statement with UTF-8 encoding + with open(TRACE_OUTPUT_FILE, "a", encoding="utf-8") as f: + f.write(f"Print in function: {function_name}, line {line_number}, file: {file_path}\n") + f.write(f" Output: {' '.join(map(str, args))}\n\n") + + # Call the original print function + original_print(*args, **kwargs) + +# Clear the output file before starting +with open(TRACE_OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("Trace Log:\n\n") + +# Override built-in print +builtins.print = traced_print + +# Import and execute the target script +script_path = "osdag/osdagMainPage.py" + +with open(script_path) as f: + code = f.read() + exec(code) + +# Restore original print +builtins.print = original_print diff --git a/src/osdag/profile_output b/src/osdag/profile_output new file mode 100644 index 000000000..dc8f0dd85 --- /dev/null +++ b/src/osdag/profile_output @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/osdag/trace_wrapper.py b/src/osdag/trace_wrapper.py index ce3c72700..d8899522b 100644 --- a/src/osdag/trace_wrapper.py +++ b/src/osdag/trace_wrapper.py @@ -1,45 +1,32 @@ import sys import os +import runpy -# File to save the trace output TRACE_OUTPUT_FILE = "trace_output.txt" - -# Path to ignore (conda environment directory) -CONDA_PATH = os.getenv('CONDA_PREFIX', '') # Automatically gets the current conda environment path +CONDA_PATH = os.getenv('CONDA_PREFIX', '') def trace_calls(frame, event, arg): - # Get the file path of the current frame file_path = frame.f_globals.get("__file__", "") - - # Ignore calls from files in the conda environment if CONDA_PATH and file_path.startswith(CONDA_PATH): return - - # Log the function call to the output file if event == "call": - # Get the caller's frame caller_frame = frame.f_back caller_file = caller_frame.f_globals.get("__file__", "unknown file") caller_line = caller_frame.f_lineno - with open(TRACE_OUTPUT_FILE, "a") as f: f.write(f"Calling function: {frame.f_code.co_name} in {file_path}\n") f.write(f" Called from: {caller_file}, line {caller_line}\n\n") return trace_calls -# Clear the output file before starting +# Clear log with open(TRACE_OUTPUT_FILE, "w") as f: f.write("Trace Log:\n\n") -# Enable tracing +# Set trace sys.settrace(trace_calls) -# Import and execute the target script -script_path = "osdag/osdagMainPage.py" - -with open(script_path) as f: - code = f.read() - exec(code) +# Run osdagMainPage as a module +runpy.run_module("osdag.osdagMainPage", run_name="__main__") -# Disable tracing +# Clear trace sys.settrace(None) diff --git a/src/osdag/trace_wrapper_unique.py b/src/osdag/trace_wrapper_unique.py new file mode 100644 index 000000000..0a3505958 --- /dev/null +++ b/src/osdag/trace_wrapper_unique.py @@ -0,0 +1,61 @@ +import sys +import os + +# Files to save the trace outputs +TRACE_OUTPUT_FILE = "trace_output.txt" +UNIQUE_FUNCTIONS_FILE = "trace_functions.txt" + +# Path to ignore (conda environment directory) +CONDA_PATH = os.getenv('CONDA_PREFIX', '') + +# Set to store unique function calls +unique_functions = set() + +def trace_calls(frame, event, arg): + # Get the file path of the current frame + file_path = frame.f_globals.get("__file__", "") + + # Ignore calls from files in the conda environment + if CONDA_PATH and file_path.startswith(CONDA_PATH): + return + + # Log function calls + if event == "call": + # Get caller information + caller_frame = frame.f_back + caller_file = caller_frame.f_globals.get("__file__", "unknown file") + caller_line = caller_frame.f_lineno + + # Log all calls to trace_output.txt + with open(TRACE_OUTPUT_FILE, "a") as f: + f.write(f"Calling function: {frame.f_code.co_name} in {file_path}\n") + f.write(f" Called from: {caller_file}, line {caller_line}\n\n") + + # Store unique function information + function_info = f"Function: {frame.f_code.co_name}\nLocation: {file_path}\n" + if function_info not in unique_functions: + unique_functions.add(function_info) + # Write to unique functions file + with open(UNIQUE_FUNCTIONS_FILE, "a") as f: + f.write(f"{function_info}\n") + + return trace_calls + +# Clear both output files before starting +with open(TRACE_OUTPUT_FILE, "w") as f: + f.write("Trace Log:\n\n") + +with open(UNIQUE_FUNCTIONS_FILE, "w") as f: + f.write("Unique Functions Log:\n\n") + +# Enable tracing +sys.settrace(trace_calls) + +# Import and execute the target script +script_path = "osdag/osdagMainPage.py" +with open(script_path) as f: + code = f.read() + exec(code) + +# Disable tracing +sys.settrace(None) \ No newline at end of file diff --git a/src/osdag/utilities/__init__.py b/src/osdag/utilities/__init__.py index 3a50f50cc..12eeb7d3b 100644 --- a/src/osdag/utilities/__init__.py +++ b/src/osdag/utilities/__init__.py @@ -40,6 +40,8 @@ Graphic3d_AspectLine3d) from OCC.Core.Aspect import Aspect_TOTP_RIGHT_LOWER, Aspect_FM_STRETCH, Aspect_FM_NONE import traceback +from OCC.Core.AIS import AIS_TextLabel + def color_the_edges(shp, display, color, width): """ @@ -106,27 +108,63 @@ def DisplayMsg(display, point, text_to_write, height=None, message_color=None, u """ :point: a gp_Pnt or gp_Pnt2d instance :text_to_write: a string - :message_color: triple with the range 0-1 + :message_color: triple with the range 0-1, e.g., (1.0, 0.0, 0.0) for red + :height: float, text height + :update: bool, whether to repaint the display """ - aPresentation = Prs3d_Presentation(display._struc_mgr) - text_aspect = Prs3d_TextAspect() - + # Handle point + if isinstance(point, gp_Pnt): + pnt = point + elif isinstance(point, gp_Pnt2d): + pnt = gp_Pnt(point.X(), point.Y(), 0.0) + else: + raise TypeError("point must be gp_Pnt or gp_Pnt2d") + + # Get the AIS_InteractiveContext from the display + # Try different ways to access the context + if hasattr(display, 'Context'): + ais_context = display.Context # Access as attribute + elif hasattr(display, '_context'): + ais_context = display._context + elif hasattr(display, 'GetContext'): + ais_context = display.GetContext() # Some implementations use methods + else: + # Fallback: try to create a text directly with the display object + return display.DisplayMessage(pnt, text_to_write, message_color or (0,0,0), height or 10) + + # Set color if message_color is not None: - text_aspect.SetColor(rgb_color("RED")) - # if height is not None: - text_aspect.Aspect() - # if isinstance(point, None): - point = gp_Pnt(point.X(), point.Y(), point.Z()) - Prs3d_Text.Draw(aPresentation, - text_aspect, - to_string(text_to_write), - point) - aPresentation.Display() - # @TODO: it would be more coherent if a AIS_InteractiveObject - # is be returned + if len(message_color) != 3: + raise ValueError("message_color must be a tuple of three floats between 0 and 1") + r, g, b = message_color + if not (0 <= r <= 1 and 0 <= g <= 1 and 0 <= b <= 1): + raise ValueError("message_color values must be between 0 and 1") + color = Quantity_Color(r, g, b, Quantity_TOC_RGB) + else: + # Default color: black + color = Quantity_Color(0.0, 0.0, 0.0, Quantity_TOC_RGB) + + # Create AIS_Text label + text_label = AIS_TextLabel() + text_label.SetText(text_to_write) + text_label.SetPosition(pnt) + text_label.SetColor(color) + + # Set height + if height is not None: + text_label.SetHeight(height) + else: + # Default height: 10 + text_label.SetHeight(20) + + # Display the text + ais_context.Display(text_label, True) + + # Update display if needed if update: display.Repaint() - return aPresentation + + return text_label # def osdag_display_msg(display, shapes, material=None, texture=None, color=None, transparency=None, update=False): # set_default_edge_style(shapes, display) diff --git a/src/osdag/utils/common/component.py b/src/osdag/utils/common/component.py index dd9ad13c9..d1ceade86 100644 --- a/src/osdag/utils/common/component.py +++ b/src/osdag/utils/common/component.py @@ -1266,7 +1266,10 @@ class ISection(Material): def __init__(self, designation, material_grade="", table=""): if table == "": table = "Beams" if designation in connectdb("Beams", "popup") else "Columns" - self.connect_to_database_update_other_attributes(table, designation, material_grade) + if table == "Channels": + self.connect_to_database_update_other_attributes_channels(table, designation, material_grade) + else: + self.connect_to_database_update_other_attributes(table, designation, material_grade) self.design_status = True self.designation = designation self.type = "Rolled" @@ -1359,6 +1362,61 @@ def connect_to_database_update_other_attributes(self, table, designation, materi conn.close() + def connect_to_database_update_other_attributes_channels(self, table, designation, material_grade=""): + conn = sqlite3.connect(PATH_TO_DATABASE) + db_query = "SELECT * FROM " + table + " WHERE Designation = ?" + cur = conn.cursor() + cur.execute(db_query, (designation,)) + row = cur.fetchone() + self.mass = row[2] + self.area = row[3] * 100 + self.depth = row[4] + self.flange_width = row[5] + self.web_thickness = row[6] + self.flange_thickness = row[7] + max_thickness = max(self.flange_thickness, self.web_thickness) + super(ISection, self).__init__(material_grade, max_thickness) + self.flange_slope = row[8] + self.root_radius = round(row[9], 2) + self.toe_radius = round(row[10], 2) + self.centre_of_greavity = round(row[11], 2) + self.mom_inertia_z = round(row[12] * 10000, 2) + self.mom_inertia_y = round(row[13] * 10000, 2) + self.rad_of_gy_z = round(row[14] * 10, 2) + self.rad_of_gy_y = round(row[15] * 10, 2) + self.elast_sec_mod_z = round(row[16] * 1000, 2) + self.elast_sec_mod_y = round(row[17] * 1000, 2) + self.plast_sec_mod_z = round(row[18], 2) + from .Section_Properties_Calculator import I_sectional_Properties + if self.plast_sec_mod_z is None: # Todo: add in database + self.plast_sec_mod_z = round(I_sectional_Properties().calc_PlasticModulusZpz(self.depth, self.flange_width, + self.web_thickness, + self.flange_thickness) * 1000, + 2) + else: + self.plast_sec_mod_z = round(row[18] * 1000, 2) + + self.plast_sec_mod_y = round(row[19] * 1000, 2) + if self.plast_sec_mod_y is None: # Todo: add in database + self.plast_sec_mod_y = round(I_sectional_Properties().calc_PlasticModulusZpy(self.depth, self.flange_width, + self.web_thickness, + self.flange_thickness) * 1000, + 2) + else: + self.plast_sec_mod_y = round(row[19] * 1000, 2) + + self.It = round(I_sectional_Properties().calc_TorsionConstantIt(self.depth, self.flange_width, + self.web_thickness, + self.flange_thickness) * 10 ** 4, 2) \ + if row[19] is None else round(row[20] * 10 ** 4, 2) + self.Iw = I_sectional_Properties().calc_WarpingConstantIw(self.depth, self.flange_width, + self.web_thickness, self.flange_thickness) * 10 ** 6 \ + if row[20] is None else round(row[21] * 10 ** 6, 2) + self.source = row[22] + self.type = 'Rolled' if row[23] is None else row[23] + + conn.close() + def tension_member_yielding(self, A_g, F_y): "design strength of members under axial tension,T_dg,as governed by yielding of gross section" "A_g = gross area of cross-section" diff --git a/src/osdag/utils/common/load.py b/src/osdag/utils/common/load.py index cbea3f876..537d46253 100644 --- a/src/osdag/utils/common/load.py +++ b/src/osdag/utils/common/load.py @@ -1,6 +1,15 @@ class Load(object): - def __init__(self, axial_force=0.0, shear_force=0.0, moment=0.0, moment_minor=0.0, unit_kNm=False): + def __init__(self, + axial_force=0.0, + shear_force=0.0, + shear_force_zz=0.0, + shear_force_yy=0.0, + moment=0.0, + moment_zz=0.0, + moment_yy=0.0, + moment_minor=0.0, + unit_kNm=False): force_multiplier = 1.0 moment_multiplier = 1.0 @@ -12,16 +21,44 @@ def __init__(self, axial_force=0.0, shear_force=0.0, moment=0.0, moment_minor=0. self.axial_force = force_multiplier * float(axial_force) else: self.axial_force = 0.0 + + ''' + Shear force + ''' if shear_force is not "": self.shear_force = force_multiplier * float(shear_force) else: self.shear_force = 0.0 + if shear_force_zz is not "": + self.shear_force_zz = force_multiplier * float(shear_force_zz) + else: + self.shear_force_zz = 0.0 + if shear_force_yy is not "": + self.shear_force_yy = force_multiplier * float(shear_force_yy) + else: + self.shear_force_yy = 0.0 + + ''' + Moment force + ''' if moment is not "": self.moment = moment_multiplier * float(moment) self.moment_minor = moment_multiplier * float(moment_minor) else: self.moment = 0.0 self.moment_minor = 0.0 + if moment_yy is not "": + self.moment_yy = moment_multiplier * float(moment_yy) + self.moment_minor = moment_multiplier * float(moment_minor) + else: + self.moment_yy = 0.0 + self.moment_minor = 0.0 + if moment_zz is not "": + self.moment_zz = moment_multiplier * float(moment_zz) + self.moment_minor = moment_multiplier * float(moment_minor) + else: + self.moment_zz = 0.0 + self.moment_minor = 0.0 print("setting factored input loads as, axial force = {0} N, shear force = {1} N, moment = {2} Nmm".format( self.axial_force, self.shear_force, self.moment)) diff --git a/src/profile_output b/src/profile_output new file mode 100644 index 0000000000000000000000000000000000000000..55348d4a36e629803bf91fa652bb9fb7d93c0b11 GIT binary patch literal 6643 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 I!XzdA7nft29{>OV literal 0 HcmV?d00001