diff --git a/.gitignore b/.gitignore index b7faf403..c1085940 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Byte-compiled / optimized / DLL files -__pycache__/ +*/__pycache__/ *.py[codz] *$py.class @@ -125,7 +125,7 @@ ipython_config.py .pixi # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ +*/__pypackages__/ # Celery stuff celerybeat-schedule diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..441bc96d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# Primary GUI dependency +PySide6>=6.5.0 \ No newline at end of file diff --git a/src/osdagbridge/__init__.py b/src/osdagbridge/__init__.py deleted file mode 100644 index a4933da9..00000000 --- a/src/osdagbridge/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""osdagbridge package.""" -__version__ = "0.0.0" diff --git a/src/osdagbridge/core/__init__.py b/src/osdagbridge/core/__init__.py deleted file mode 100644 index 62df716e..00000000 --- a/src/osdagbridge/core/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Core package for OsdagBridge""" -from .models import * diff --git a/src/osdagbridge/core/bridge_components/super_structure/girder/properties.py b/src/osdagbridge/core/bridge_components/super_structure/girder/properties.py index b363f1e5..d408f733 100644 --- a/src/osdagbridge/core/bridge_components/super_structure/girder/properties.py +++ b/src/osdagbridge/core/bridge_components/super_structure/girder/properties.py @@ -1,3 +1,157 @@ -"""Section property calculations (stub).""" -def area(): - return 0.0 +"""Access rolled girder properties sourced from the bundled SQLite table. + +The beam geometry and sectional properties are stored inside +``core/data/ResourceFiles/Intg_osdag.sqlite`` and originate from +IS 808:1989 (Rev.). This module provides a thin loader that exposes the +data both as rich ``BeamSection`` records and in the minimal format that +the UI preview widgets currently expect. +""" + +from __future__ import annotations + +import sqlite3 +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any, Dict, Optional + + +@dataclass(frozen=True) +class BeamSection: + """Representation of a rolled steel beam from the reference table.""" + + id: int + designation: str + mass_per_meter_kg: float + area_cm2: float + depth_mm: float + flange_width_mm: float + web_thickness_mm: float + flange_thickness_mm: float + flange_slope: Optional[float] + root_radius_r1_mm: Optional[float] + root_radius_r2_mm: Optional[float] + moment_of_inertia_zz_cm4: Optional[float] + moment_of_inertia_yy_cm4: Optional[float] + radius_of_gyration_z_cm: Optional[float] + radius_of_gyration_y_cm: Optional[float] + elastic_section_modulus_z_cm3: Optional[float] + elastic_section_modulus_y_cm3: Optional[float] + plastic_section_modulus_z_cm3: Optional[float] + plastic_section_modulus_y_cm3: Optional[float] + torsion_constant_cm4: Optional[float] + warping_constant_cm6: Optional[float] + source: Optional[str] + section_type: Optional[str] + + @property + def outline_dict(self) -> Dict[str, float]: + """Return the minimal dictionary expected by preview widgets.""" + + return { + "designation": self.designation, + "depth_mm": self.depth_mm, + "top_flange_width_mm": self.flange_width_mm, + "bottom_flange_width_mm": self.flange_width_mm, + "web_thickness_mm": self.web_thickness_mm, + "top_flange_thickness_mm": self.flange_thickness_mm, + "bottom_flange_thickness_mm": self.flange_thickness_mm, + } + + def as_dict(self) -> Dict[str, Any]: + """Expose the full record as a plain dictionary copy.""" + + return asdict(self) + + +# Backwards compatibility for callers importing RolledSection directly. +RolledSection = BeamSection + +_DB_PATH = Path(__file__).resolve().parents[3] / "data" / "ResourceFiles" / "Intg_osdag.sqlite" +_BEAM_CACHE: Optional[Dict[str, BeamSection]] = None + + +def _text_or_none(value: Optional[str]) -> Optional[str]: + if value is None: + return None + text = value.strip() + return text or None + + +def _optional_float(value: Optional[float]) -> Optional[float]: + return None if value is None else float(value) + + +def _load_beam_sections() -> Dict[str, BeamSection]: + if not _DB_PATH.exists(): # pragma: no cover - defensive guard + raise FileNotFoundError(f"Beam property database not found at {_DB_PATH}") + + with sqlite3.connect(_DB_PATH) as connection: + connection.row_factory = sqlite3.Row + rows = connection.execute("SELECT * FROM Beams").fetchall() + + beam_map: Dict[str, BeamSection] = {} + for row in rows: + designation = row["Designation"] + beam = BeamSection( + id=int(row["Id"]), + designation=designation, + mass_per_meter_kg=float(row["Mass"]), + area_cm2=float(row["Area"]), + depth_mm=float(row["D"]), + flange_width_mm=float(row["B"]), + web_thickness_mm=float(row["tw"]), + flange_thickness_mm=float(row["T"]), + flange_slope=_optional_float(row["FlangeSlope"]), + root_radius_r1_mm=_optional_float(row["R1"]), + root_radius_r2_mm=_optional_float(row["R2"]), + moment_of_inertia_zz_cm4=_optional_float(row["Iz"]), + moment_of_inertia_yy_cm4=_optional_float(row["Iy"]), + radius_of_gyration_z_cm=_optional_float(row["rz"]), + radius_of_gyration_y_cm=_optional_float(row["ry"]), + elastic_section_modulus_z_cm3=_optional_float(row["Zz"]), + elastic_section_modulus_y_cm3=_optional_float(row["Zy"]), + plastic_section_modulus_z_cm3=_optional_float(row["Zpz"]), + plastic_section_modulus_y_cm3=_optional_float(row["Zpy"]), + torsion_constant_cm4=_optional_float(row["It"]), + warping_constant_cm6=_optional_float(row["Iw"]), + source=_text_or_none(row["Source"]), + section_type=_text_or_none(row["Type"]), + ) + beam_map[designation] = beam + + return beam_map + + +def _beams() -> Dict[str, BeamSection]: + global _BEAM_CACHE + if _BEAM_CACHE is None: + _BEAM_CACHE = _load_beam_sections() + return _BEAM_CACHE + + +def get_beam_profile(designation: str) -> Optional[BeamSection]: + """Return the full beam profile record from the SQLite table.""" + + return _beams().get(designation) + + +def get_rolled_section(designation: str) -> Optional[Dict[str, float]]: + """Return the rolled section outline expected by existing UI code.""" + + section = get_beam_profile(designation) + return section.outline_dict if section else None + + +def list_available_sections() -> Dict[str, BeamSection]: + """Expose the cached beam table for downstream consumers.""" + + return dict(_beams()) + + +__all__ = [ + "BeamSection", + "RolledSection", + "get_beam_profile", + "get_rolled_section", + "list_available_sections", +] diff --git a/src/osdagbridge/core/bridge_types/plate_girder/ui_fields.py b/src/osdagbridge/core/bridge_types/plate_girder/ui_fields.py new file mode 100644 index 00000000..11851762 --- /dev/null +++ b/src/osdagbridge/core/bridge_types/plate_girder/ui_fields.py @@ -0,0 +1,366 @@ +from osdagbridge.core.utils.common import * +""" +( + key, + display_name, + ui_type, + values, + is_visible, + validator, + ui_config_dict +) + +""" +class FrontendData: + """Backend for Highway Bridge Design""" + + def __init__(self): + self.module = KEY_DISP_FINPLATE + self.design_status = False + self.design_button_status = False + + def input_values(self): + """Return structured list of input definitions for the UI""" + options_list = [] + + options_list.append( + (KEY_MODULE, KEY_DISP_FINPLATE, TYPE_MODULE, None, True, 'No Validator', {}) + ) + + # Type of Structure + options_list.append( + ( + "section_structure", + DISP_TITLE_STRUCTURE, + TYPE_TITLE, + None, + True, + 'No Validator', + { + "container": "main", + "post_note": { + "text": "*Other structures not included", + "attr": "structure_note", + }, + }, + ) + ) + options_list.append( + ( + KEY_STRUCTURE_TYPE, + KEY_DISP_STRUCTURE_TYPE, + TYPE_COMBOBOX, + VALUES_STRUCTURE_TYPE, + True, + 'No Validator', + {}, + ) + ) + + # Project Location (custom content handled in dock) + options_list.append( + ( + "section_project_location", + DISP_TITLE_PROJECT, + TYPE_TITLE, + None, + True, + 'No Validator', + { + "container": "main", + "custom_content": "project_location", + "show_group_title": False, + "header_label": "Project Location*", + "button_rows": [ + { + "type": "project_location", + "buttons": [ + { + "text": "Add Here", + "action": "show_project_location_dialog", + } + ], + } + ], + }, + ) + ) + + # Geometric Details + options_list.append( + ( + "section_geometric", + DISP_TITLE_GEOMETRIC, + TYPE_TITLE, + None, + True, + 'No Validator', + { + "container": "superstructure", + "post_rows": [ + { + "type": "additional_geometry", + "label": "Additional Geometry", + "buttons": [ + { + "text": "Modify Here", + "action": "show_additional_inputs", + } + ], + } + ], + }, + ) + ) + options_list.append( + ( + KEY_SPAN, + KEY_DISP_SPAN, + TYPE_TEXTBOX, + None, + True, + 'Double Validator', + {"label": "Span*"}, + ) + ) + options_list.append( + ( + KEY_CARRIAGEWAY_WIDTH, + KEY_DISP_CARRIAGEWAY_WIDTH, + TYPE_TEXTBOX, + None, + True, + 'Double Validator', + {"label": "Carriageway Width*"}, + ) + ) + options_list.append( + ( + KEY_INCLUDE_MEDIAN, + "Include Median", + TYPE_COMBOBOX, + VALUES_YES_NO, + True, + 'No Validator', + {"label": "Include Median", "default": "No", "add_stretch": True}, + ) + ) + options_list.append( + ( + KEY_FOOTPATH, + KEY_DISP_FOOTPATH, + TYPE_COMBOBOX, + VALUES_FOOTPATH, + True, + 'No Validator', + {"label": "Footpath", "default": "None"}, + ) + ) + options_list.append( + ( + KEY_SKEW_ANGLE, + KEY_DISP_SKEW_ANGLE, + TYPE_TEXTBOX, + None, + True, + 'Double Validator', + {"label": "Skew Angle"}, + ) + ) + + # Material Inputs + options_list.append( + ( + "section_material", + DISP_TITLE_MATERIAL, + TYPE_TITLE, + None, + True, + 'No Validator', + { + "container": "superstructure", + "post_rows": [ + { + "type": "material_properties", + "label": "Properties", + "buttons": [ + { + "text": "Modify Here", + "action": "show_material_properties_dialog", + } + ], + } + ], + }, + ) + ) + material_values = connectdb("Material") + options_list.append( + ( + KEY_GIRDER, + KEY_DISP_GIRDER, + TYPE_COMBOBOX, + material_values, + True, + 'No Validator', + {"label": "Girder"}, + ) + ) + options_list.append( + ( + KEY_CROSS_BRACING, + KEY_DISP_CROSS_BRACING, + TYPE_COMBOBOX, + material_values, + True, + 'No Validator', + {"label": "Cross Bracing"}, + ) + ) + options_list.append( + ( + KEY_END_DIAPHRAGM, + KEY_DISP_END_DIAPHRAGM, + TYPE_COMBOBOX, + material_values, + True, + 'No Validator', + {"label": "End Diaphragm"}, + ) + ) + options_list.append( + ( + KEY_DECK_CONCRETE_GRADE_BASIC, + KEY_DISP_DECK_CONCRETE_GRADE, + TYPE_COMBOBOX, + VALUES_DECK_CONCRETE_GRADE, + True, + 'No Validator', + {"label": "Deck", "default": "M 25"}, + ) + ) + + return options_list + + def set_osdaglogger(self, key): + """Logger setup""" + print("Logger set up (mock)") + + def output_values(self, flag=None): + """Return output dock definitions using the same tuple structure as input_values.""" + outputs = [] + + outputs.append( + ( + "section_output_analysis", + "Analysis Results", + TYPE_TITLE, + None, + True, + "No Validator", + { + "kind": "analysis", + "fields": [ + ( + "analysis_member", + "Member:", + "combobox", + ["All"], + True, + "No Validator", + {"label_min_width": 100}, + ), + ( + "analysis_load_combination", + "Load Combination:", + "combobox", + ["Envelope"], + True, + "No Validator", + {"label_min_width": 100}, + ), + ( + "analysis_forces", + "Forces", + "checkbox_grid", + [ + ["Fx", "Mx", "Dx"], + ["Fy", "My", "Dy"], + ["Fz", "Mz", "Dz"], + ], + True, + "No Validator", + {}, + ), + ( + "analysis_display_options", + "Display Options:", + "checkbox_row", + ["Max", "Min"], + True, + "No Validator", + {}, + ), + ( + "analysis_utilization", + "Controlling Utilization Ratio", + "checkbox", + None, + True, + "No Validator", + {}, + ), + ], + }, + ) + ) + + outputs.append( + ( + "section_output_superstructure", + "Superstructure", + TYPE_TITLE, + None, + True, + "No Validator", + { + "kind": "design", + "rows": [ + { + "label": "Steel Design", + "buttons": [ + {"text": "Here", "action": "show_additional_inputs"}, + ], + }, + { + "label": "Deck Design", + "buttons": [ + {"text": "Here", "action": "show_additional_inputs"}, + ], + }, + ] + }, + ) + ) + + outputs.append( + ( + "section_output_substructure", + "Substructure", + TYPE_TITLE, + None, + True, + "No Validator", + { + "kind": "design", + "rows": [], + }, + ) + ) + + return outputs + + def func_for_validation(self, design_inputs): + """Validation Function""" + return None + diff --git a/src/osdagbridge/core/data/ResourceFiles/Intg_osdag.sql b/src/osdagbridge/core/data/ResourceFiles/Intg_osdag.sql new file mode 100644 index 00000000..8000cd4f --- /dev/null +++ b/src/osdagbridge/core/data/ResourceFiles/Intg_osdag.sql @@ -0,0 +1,1360 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE IF NOT EXISTS "Bolt" ( + "Bolt_diameter" TEXT +); +INSERT INTO Bolt VALUES('8'); +INSERT INTO Bolt VALUES('10'); +INSERT INTO Bolt VALUES('12'); +INSERT INTO Bolt VALUES('16'); +INSERT INTO Bolt VALUES('20'); +INSERT INTO Bolt VALUES('24'); +INSERT INTO Bolt VALUES('30'); +INSERT INTO Bolt VALUES('36'); +INSERT INTO Bolt VALUES('42'); +INSERT INTO Bolt VALUES('48'); +INSERT INTO Bolt VALUES('56'); +INSERT INTO Bolt VALUES('64'); +INSERT INTO Bolt VALUES('14'); +INSERT INTO Bolt VALUES('18'); +INSERT INTO Bolt VALUES('22'); +INSERT INTO Bolt VALUES('27'); +INSERT INTO Bolt VALUES('33'); +INSERT INTO Bolt VALUES('39'); +INSERT INTO Bolt VALUES('45'); +INSERT INTO Bolt VALUES('52'); +INSERT INTO Bolt VALUES('60'); +CREATE TABLE IF NOT EXISTS "Anchor_Bolt" ( + "Diameter" INTEGER +); +INSERT INTO Anchor_Bolt VALUES('M8'); +INSERT INTO Anchor_Bolt VALUES('M10'); +INSERT INTO Anchor_Bolt VALUES('M12'); +INSERT INTO Anchor_Bolt VALUES('M16'); +INSERT INTO Anchor_Bolt VALUES('M20'); +INSERT INTO Anchor_Bolt VALUES('M24'); +INSERT INTO Anchor_Bolt VALUES('M30'); +INSERT INTO Anchor_Bolt VALUES('M36'); +INSERT INTO Anchor_Bolt VALUES('M42'); +INSERT INTO Anchor_Bolt VALUES('M48'); +INSERT INTO Anchor_Bolt VALUES('M56'); +INSERT INTO Anchor_Bolt VALUES('M64'); +INSERT INTO Anchor_Bolt VALUES('M72'); +CREATE TABLE IF NOT EXISTS "Angle_Pitch" ( + "ID" INTEGER UNIQUE, + "Nominal_Leg" INTEGER, + "Max_Bolt_Dia" INTEGER, + "Bolt_lines" INTEGER, + "S1" INTEGER, + "S2" INTEGER, + "S3" INTEGER +); +INSERT INTO Angle_Pitch VALUES(1,50,12,1,28,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(2,60,16,1,35,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(3,65,20,1,35,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(4,70,20,1,40,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(5,75,20,1,45,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(6,80,20,1,45,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(7,90,24,1,50,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(8,100,24,1,55,NULL,NULL); +INSERT INTO Angle_Pitch VALUES(9,120,16,2,45,50,NULL); +INSERT INTO Angle_Pitch VALUES(10,125,20,2,45,50,NULL); +INSERT INTO Angle_Pitch VALUES(11,150,20,2,55,55,NULL); +INSERT INTO Angle_Pitch VALUES(13,200,30,2,75,75,NULL); +INSERT INTO Angle_Pitch VALUES(12,200,20,3,55,55,55); +CREATE TABLE IF NOT EXISTS "Material" ( + "Grade" TEXT, + "Yield Stress (< 20)" INTEGER, + "Yield Stress (20 -40)" INTEGER, + "Yield Stress (> 40)" INTEGER, + "Ultimate Tensile Stress" INTEGER, + "Elongation " INTEGER +); +INSERT INTO Material VALUES('E 165 (Fe 290)',165,165,165,290,23); +INSERT INTO Material VALUES('E 250 (Fe 410 W)A',250,240,230,410,23); +INSERT INTO Material VALUES('E 250 (Fe 410 W)B',250,240,230,410,23); +INSERT INTO Material VALUES('E 250 (Fe 410 W)C',250,240,230,410,23); +INSERT INTO Material VALUES('E 300 (Fe 440)',300,290,280,440,22); +INSERT INTO Material VALUES('E 350 (Fe 490)',350,330,320,490,22); +INSERT INTO Material VALUES('E 410 (Fe 540)',410,390,380,540,20); +INSERT INTO Material VALUES('E 450 (Fe 570)D',450,430,420,570,20); +INSERT INTO Material VALUES('E 450 (Fe 590) E',450,430,420,590,20); +INSERT INTO Material VALUES('Cus_400_500_600_1400',400,500,600,1400,20); +CREATE TABLE IF NOT EXISTS "Bolt_fy_fu" ( + `Property_Class` NUMERIC, + `Diameter_min` INTEGER, + `Diameter_max` INTEGER, + `fy` NUMERIC, + `fu` NUMERIC +); +INSERT INTO Bolt_fy_fu VALUES(4.6,0,100,240,400); +INSERT INTO Bolt_fy_fu VALUES(4.8,0,100,340,420); +INSERT INTO Bolt_fy_fu VALUES(5.6,0,100,300,500); +INSERT INTO Bolt_fy_fu VALUES(5.8,0,100,420,520); +INSERT INTO Bolt_fy_fu VALUES(3.6,0,100,190,330); +INSERT INTO Bolt_fy_fu VALUES(6.8,0,100,480,600); +INSERT INTO Bolt_fy_fu VALUES(8.8,0,16,640,800); +INSERT INTO Bolt_fy_fu VALUES(8.8,16,100,660,830); +INSERT INTO Bolt_fy_fu VALUES(9.8,0,100,720,900); +INSERT INTO Bolt_fy_fu VALUES(10.9,0,100,940,1040); +INSERT INTO Bolt_fy_fu VALUES(12.9,0,100,1100,1220); +CREATE TABLE IF NOT EXISTS "UnequalAngle" ( + "Id" INTEGER NOT NULL, + "Designation" VARCHAR(50), + "Mass" REAL(10 , 2), + "Area" REAL(10 , 2), + "a" REAL(10 , 2), + "b" REAL(10 , 2), + "t" REAL(10 , 2), + "R1" REAL(10 , 2), + "R2" REAL(10 , 2), + "Cz" REAL(10 , 2), + "Cy" REAL(10 , 2), + "Iz" REAL(10 , 2), + "Iy" REAL(10 , 2), + "Alpha" REAL(10 , 2), + "Iu(max)" REAL(10 , 2), + "Iv(min)" REAL(10 , 2), + "rz" REAL(10 , 2), + "ry" REAL(10 , 2), + "ru(max)" REAL(10 , 2), + "rv(min)" REAL(10 , 2), + "Zz" REAL(10 , 2), + "Zy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "Source" VARCHAR(100), + "It" REAL(10 , 2), + PRIMARY KEY("Id") +); +INSERT INTO UnequalAngle VALUES(1,'∠ 30 ⅹ 20ⅹ 3',1.14,1.45,30.0,20.0,3.0,4.5,0.0,0.51,0.99,1.29,0.46,1.05,1.47,0.27,0.94,0.56,1.01,0.43,0.64,0.31,1.16,0.56,'IS808_Rev',0.042000000000000001776); +INSERT INTO UnequalAngle VALUES(2,'∠ 30 ⅹ 20ⅹ 4',1.48,1.88,30.0,20.0,4.0,4.5,0.0,0.55,1.04,1.63,0.57,0.4,1.85,0.34,0.93,0.55,0.99,0.43,0.83,0.39,1.48,0.73,'IS808_Rev',0.098000000000000024868); +INSERT INTO UnequalAngle VALUES(3,'∠ 30 ⅹ 20ⅹ 5',1.8,2.29,30.0,20.0,5.0,4.5,0.0,0.58,1.07,1.93,0.67,0.39,2.19,0.41,0.92,0.54,0.98,0.42,1.0,0.47,1.79,0.9,'IS808_Rev',0.18700000000000001065); +INSERT INTO UnequalAngle VALUES(4,'∠ 40 ⅹ 25ⅹ 3',1.5,1.91,40.0,25.0,3.0,5.0,0.0,0.59,1.32,3.11,0.94,0.37,3.48,0.57,1.27,0.7,1.35,0.54,1.16,0.49,2.08,0.9,'IS808_Rev',0.055); +INSERT INTO UnequalAngle VALUES(5,'∠ 40 ⅹ 25ⅹ 4',1.96,2.49,40.0,25.0,4.0,5.0,0.0,0.63,1.36,3.97,1.19,0.36,4.44,0.72,1.26,0.69,1.33,0.54,1.5,0.64,2.69,1.18,'IS808_Rev',0.13); +INSERT INTO UnequalAngle VALUES(6,'∠ 40 ⅹ 25ⅹ 5',2.4,3.05,40.0,25.0,5.0,5.0,0.0,0.67,1.4,4.76,1.42,0.36,5.31,0.87,1.25,0.68,1.32,0.53,1.83,0.77,3.27,1.45,'IS808_Rev',0.25); +INSERT INTO UnequalAngle VALUES(7,'∠ 40 ⅹ 25ⅹ 6',2.82,3.59,40.0,25.0,6.0,5.0,0.0,0.7,1.44,5.5,1.62,0.35,6.1,1.02,1.24,0.67,1.3,0.53,2.15,0.9,3.81,1.72,'IS808_Rev',0.42400000000000002131); +INSERT INTO UnequalAngle VALUES(8,'∠ 45 ⅹ 30ⅹ 3',1.74,2.21,45.0,30.0,3.0,5.0,0.0,0.71,1.44,4.57,1.65,0.41,5.26,0.96,1.44,0.86,1.54,0.66,1.49,0.72,2.7,1.29,'IS808_Rev',0.064000000000000003552); +INSERT INTO UnequalAngle VALUES(9,'∠ 45 ⅹ 30ⅹ 4',2.27,2.89,45.0,30.0,4.0,5.0,0.0,0.74,1.48,5.87,2.1,0.41,6.75,1.22,1.42,0.85,1.53,0.65,1.95,0.93,3.5,1.69,'IS808_Rev',0.15099999999999999644); +INSERT INTO UnequalAngle VALUES(10,'∠ 45 ⅹ 30ⅹ 5',2.79,3.55,45.0,30.0,5.0,5.0,0.0,0.78,1.52,7.08,2.51,0.4,8.11,1.48,1.41,0.84,1.51,0.64,2.38,1.13,4.27,2.08,'IS808_Rev',0.29099999999999997868); +INSERT INTO UnequalAngle VALUES(11,'∠ 45 ⅹ 30ⅹ 6',3.29,4.19,45.0,30.0,6.0,5.0,0.0,0.82,1.56,8.21,2.89,0.4,9.37,1.73,1.4,0.83,1.49,0.64,2.79,1.32,5.0,2.46,'IS808_Rev',0.49599999999999999644); +INSERT INTO UnequalAngle VALUES(12,'∠ 50 ⅹ30ⅹ 3',1.86,2.37,50.0,30.0,3.0,5.5,0.0,0.67,1.64,6.13,1.69,0.35,6.79,1.03,1.61,0.84,1.69,0.66,1.83,0.73,3.28,1.31,'IS808_Rev',0.069000000000000003552); +INSERT INTO UnequalAngle VALUES(13,'∠ 50 ⅹ30ⅹ 4',2.44,3.1,50.0,30.0,4.0,5.5,0.0,0.71,1.69,7.89,2.15,0.34,8.73,1.32,1.59,0.83,1.68,0.65,2.38,0.94,4.26,1.72,'IS808_Rev',0.16200000000000001065); +INSERT INTO UnequalAngle VALUES(14,'∠ 50 ⅹ30ⅹ 5',2.99,3.81,50.0,30.0,5.0,5.5,0.0,0.75,1.73,9.53,2.58,0.34,10.5,1.59,1.58,0.82,1.66,0.65,2.92,1.15,5.19,2.13,'IS808_Rev',0.31200000000000001065); +INSERT INTO UnequalAngle VALUES(15,'∠ 50 ⅹ30ⅹ 6',3.54,4.5,50.0,30.0,6.0,5.5,0.0,0.79,1.77,11.1,2.97,0.33,12.2,1.86,1.57,0.81,1.64,0.64,3.43,1.34,6.09,2.52,'IS808_Rev',0.53200000000000002842); +INSERT INTO UnequalAngle VALUES(16,'∠ 60ⅹ 40ⅹ 5',3.79,4.83,60.0,40.0,5.0,6.0,0.0,0.98,1.97,17.5,6.28,0.41,20.2,3.65,1.91,1.14,2.04,0.87,4.35,2.08,7.83,3.77,'IS808_Rev',0.39500000000000001776); +INSERT INTO UnequalAngle VALUES(17,'∠ 60ⅹ 40ⅹ 6',4.49,5.72,60.0,40.0,6.0,6.0,0.0,1.02,2.01,20.5,7.29,0.41,23.5,4.26,1.89,1.13,2.03,0.86,5.13,2.45,9.21,4.47,'IS808_Rev',0.67600000000000015631); +INSERT INTO UnequalAngle VALUES(18,'∠ 60ⅹ 40ⅹ 8',5.84,7.44,60.0,40.0,8.0,6.0,0.0,1.09,2.08,25.9,9.12,0.4,29.6,5.45,1.87,1.11,1.99,0.86,6.62,3.14,11.8,5.83,'IS808_Rev',1.57); +INSERT INTO UnequalAngle VALUES(19,'∠ 65 ⅹ45ⅹ 5',4.18,5.33,65.0,45.0,5.0,6.0,0.0,1.1,2.09,22.8,9.02,0.44,26.7,5.12,2.07,1.3,2.24,0.98,5.16,2.65,9.33,4.77,'IS808_Rev',0.43700000000000001065); +INSERT INTO UnequalAngle VALUES(20,'∠ 65 ⅹ45ⅹ 6',4.96,6.32,65.0,45.0,6.0,6.0,0.0,1.14,2.13,26.7,10.5,0.44,31.2,5.99,2.06,1.29,2.22,0.97,6.1,3.12,11.0,5.66,'IS808_Rev',0.74800000000000004263); +INSERT INTO UnequalAngle VALUES(21,'∠ 65 ⅹ45ⅹ 8',6.47,8.24,65.0,45.0,8.0,6.0,0.0,1.21,2.2,33.9,13.2,0.43,39.5,7.66,2.03,1.27,2.19,0.96,7.89,4.02,14.1,7.39,'IS808_Rev',1.74); +INSERT INTO UnequalAngle VALUES(22,'∠ 70 ⅹ45ⅹ 5',4.39,5.59,70.0,45.0,5.0,6.5,0.0,1.06,2.29,28.0,9.2,0.39,31.8,5.42,2.24,1.28,2.39,0.98,5.95,2.68,10.7,4.82,'IS808_Rev',0.4580000000000000071); +INSERT INTO UnequalAngle VALUES(23,'∠ 70 ⅹ45ⅹ 6',5.21,6.63,70.0,45.0,6.0,6.5,0.0,1.1,2.33,32.8,10.7,0.39,37.2,6.34,2.23,1.27,2.37,0.98,7.04,3.15,12.6,5.72,'IS808_Rev',0.78399999999999998578); +INSERT INTO UnequalAngle VALUES(24,'∠ 70 ⅹ45ⅹ 8',6.79,8.65,70.0,45.0,8.0,6.5,0.0,1.18,2.41,41.8,13.5,0.38,47.2,8.1,2.2,1.25,2.34,0.97,9.12,4.06,16.3,7.5,'IS808_Rev',1.82); +INSERT INTO UnequalAngle VALUES(25,'∠ 70 ⅹ45ⅹ 10',8.31,10.5,70.0,45.0,10.0,6.5,0.0,1.25,2.49,50.0,16.0,0.37,56.2,9.81,2.17,1.23,2.3,0.96,11.0,4.91,19.7,9.22,'IS808_Rev',3.5); +INSERT INTO UnequalAngle VALUES(26,'∠ 75 ⅹ 50ⅹ 5',4.78,6.09,75.0,50.0,5.0,6.5,0.0,1.18,2.41,35.1,12.7,0.41,40.5,7.32,2.4,1.44,2.58,1.1,6.9,3.32,12.4,5.95,'IS808_Rev',0.5); +INSERT INTO UnequalAngle VALUES(27,'∠ 75 ⅹ 50ⅹ 6',5.68,7.23,75.0,50.0,6.0,6.5,0.0,1.22,2.45,41.2,14.8,0.41,47.5,8.57,2.39,1.43,2.56,1.09,8.17,3.92,14.7,7.07,'IS808_Rev',0.85600000000000004973); +INSERT INTO UnequalAngle VALUES(28,'∠ 75 ⅹ 50ⅹ 8',7.42,9.45,75.0,50.0,8.0,6.5,0.0,1.29,2.53,52.7,18.7,0.41,60.5,10.9,2.36,1.41,2.53,1.08,10.6,5.05,19.0,9.25,'IS808_Rev',1.99); +INSERT INTO UnequalAngle VALUES(29,'∠ 75 ⅹ 50ⅹ 10',9.1,11.5,75.0,50.0,10.0,6.5,0.0,1.37,2.61,63.2,22.3,0.4,72.2,13.3,2.34,1.39,2.5,1.07,12.9,6.13,23.1,11.3,'IS808_Rev',3.83); +INSERT INTO UnequalAngle VALUES(30,'∠ 80ⅹ 50ⅹ 5',4.99,6.36,80.0,50.0,5.0,7.0,0.0,1.14,2.62,42.0,12.9,0.37,47.3,7.68,2.57,1.43,2.73,1.1,7.81,3.34,14.0,5.99,'IS808_Rev',0.52); +INSERT INTO UnequalAngle VALUES(31,'∠ 80ⅹ 50ⅹ 6',5.92,7.55,80.0,50.0,6.0,7.0,0.0,1.18,2.66,49.4,15.1,0.37,55.5,8.99,2.56,1.41,2.71,1.09,9.25,3.95,16.5,7.13,'IS808_Rev',0.89199999999999999289); +INSERT INTO UnequalAngle VALUES(32,'∠ 80ⅹ 50ⅹ 8',7.74,9.87,80.0,50.0,8.0,7.0,0.0,1.26,2.74,63.2,19.1,0.37,70.8,11.5,2.53,1.39,2.68,1.08,12.0,5.09,21.4,9.36,'IS808_Rev',2.08); +INSERT INTO UnequalAngle VALUES(33,'∠ 80ⅹ 50ⅹ 10',9.5,12.1,80.0,50.0,10.0,7.0,0.0,1.33,2.82,76.0,22.7,0.36,84.7,13.9,2.5,1.37,2.65,1.07,14.6,6.18,26.0,11.5,'IS808_Rev',4.0); +INSERT INTO UnequalAngle VALUES(34,'∠ 90 ⅹ 60ⅹ 6',6.88,8.76,90.0,60.0,6.0,7.5,0.0,1.42,2.9,72.8,26.3,0.41,84.0,15.2,2.88,1.73,3.1,1.32,11.9,5.74,21.5,10.2,'IS808_Rev',1.03); +INSERT INTO UnequalAngle VALUES(35,'∠ 90 ⅹ 60ⅹ 8',9.01,11.4,90.0,60.0,8.0,7.5,0.0,1.49,2.98,93.6,33.5,0.41,107.0,19.5,2.86,1.71,3.06,1.3,15.5,7.44,27.9,13.4,'IS808_Rev',2.42); +INSERT INTO UnequalAngle VALUES(36,'∠ 90 ⅹ 60ⅹ 10',11.08,14.1,90.0,60.0,10.0,7.5,0.0,1.57,3.06,113.0,40.1,0.41,129.0,23.6,2.83,1.69,3.03,1.29,19.0,9.05,34.1,16.6,'IS808_Rev',4.66); +INSERT INTO UnequalAngle VALUES(37,'∠ 90 ⅹ 60ⅹ 12',13.09,16.6,90.0,60.0,12.0,7.5,0.0,1.64,3.13,131.0,46.2,0.4,149.0,27.6,2.8,1.66,3.0,1.29,22.3,10.6,39.9,19.7,'IS808_Rev',7.94); +INSERT INTO UnequalAngle VALUES(38,'∠100 ⅹ 65ⅹ 6',7.6,9.68,100.0,65.0,6.0,8.0,0.0,1.5,3.22,100.0,34.0,0.4,114.0,19.8,3.22,1.88,3.44,1.43,14.8,6.8,26.6,12.1,'IS808_Rev',1.14); +INSERT INTO UnequalAngle VALUES(39,'∠100 ⅹ 65ⅹ 8',9.97,12.7,100.0,65.0,8.0,8.0,0.0,1.57,3.3,129.0,43.5,0.4,147.0,25.5,3.19,1.85,3.4,1.42,19.3,8.8,34.6,15.9,'IS808_Rev',2.67); +INSERT INTO UnequalAngle VALUES(40,'∠100 ⅹ 65ⅹ 10',12.28,15.6,100.0,65.0,10.0,8.0,0.0,1.65,3.38,156.0,52.2,0.39,177.0,30.9,3.16,1.83,3.37,1.4,23.6,10.8,42.3,19.7,'IS808_Rev',5.16); +INSERT INTO UnequalAngle VALUES(41,'∠100 ⅹ 75ⅹ 6',8.08,10.3,100.0,75.0,6.0,8.5,0.0,1.82,3.05,105.0,51.2,0.5,128.0,27.6,3.19,2.23,3.54,1.64,15.1,9.0,27.4,16.0,'IS808_Rev',1.21); +INSERT INTO UnequalAngle VALUES(42,'∠100 ⅹ 75ⅹ 8',10.61,13.5,100.0,75.0,8.0,8.5,0.0,1.89,3.13,135.0,65.7,0.5,165.0,35.5,3.17,2.21,3.5,1.62,19.7,11.7,35.8,21.0,'IS808_Rev',2.85); +INSERT INTO UnequalAngle VALUES(43,'∠100 ⅹ 75ⅹ 10',13.07,16.6,100.0,75.0,10.0,8.5,0.0,1.97,3.21,164.0,79.2,0.5,200.0,43.0,3.14,2.18,3.47,1.61,24.2,14.3,43.8,25.9,'IS808_Rev',5.5); +INSERT INTO UnequalAngle VALUES(44,'∠100 ⅹ 75ⅹ 12',15.48,19.7,100.0,75.0,12.0,8.5,0.0,2.04,3.28,191.0,91.7,0.5,232.0,50.4,3.11,2.16,3.43,1.6,28.5,16.8,51.4,30.6,'IS808_Rev',9.38); +INSERT INTO UnequalAngle VALUES(45,'∠ 125 ⅹ 75ⅹ 6',9.27,11.8,125.0,75.0,6.0,9.0,0.0,1.62,4.08,194.0,54.3,0.35,215.0,32.7,4.05,2.14,4.27,1.66,23.1,9.2,41.3,16.4,'IS808_Rev',1.39); +INSERT INTO UnequalAngle VALUES(46,'∠ 125 ⅹ 75ⅹ 8',12.19,15.5,125.0,75.0,8.0,9.0,0.0,1.7,4.17,251.0,69.7,0.35,279.0,42.1,4.03,2.12,4.24,1.65,30.2,12.0,53.9,21.6,'IS808_Rev',3.27); +INSERT INTO UnequalAngle VALUES(47,'∠ 125 ⅹ 75ⅹ 10',15.05,19.1,125.0,75.0,10.0,9.0,0.0,1.78,4.26,306.0,84.1,0.35,339.0,51.0,4.0,2.09,4.21,1.63,37.2,14.7,66.2,26.7,'IS808_Rev',6.33); +INSERT INTO UnequalAngle VALUES(48,'∠125 ⅹ 95 ⅹ 6',10.14,12.9,125.0,95.0,6.0,9.0,4.8,2.24,3.72,205.0,103.0,0.52,254.0,55.0,3.99,2.83,4.44,2.06,23.4,14.3,42.9,25.5,'IS808_Rev',1.54); +INSERT INTO UnequalAngle VALUES(49,'∠125 ⅹ 95ⅹ 8',13.37,17.0,125.0,95.0,8.0,9.0,4.8,2.32,3.8,268.0,134.0,0.52,331.0,71.4,3.97,2.81,4.41,2.05,30.9,18.8,56.4,33.7,'IS808_Rev',3.61); +INSERT INTO UnequalAngle VALUES(50,'∠125 ⅹ 95ⅹ 10',16.54,21.0,125.0,95.0,10.0,9.0,4.8,2.4,3.89,328.0,164.0,0.51,404.0,87.3,3.94,2.79,4.38,2.04,38.1,23.1,69.4,41.7,'IS808_Rev',7.0); +INSERT INTO UnequalAngle VALUES(51,'∠125 ⅹ 95ⅹ 12',19.65,25.0,125.0,95.0,12.0,9.0,4.8,2.48,3.97,384.0,191.0,0.51,473.0,102.0,3.92,2.77,4.35,2.02,45.1,27.3,82.0,49.5,'IS808_Rev',11.9); +INSERT INTO UnequalAngle VALUES(52,'∠150 ⅹ 115ⅹ 8',16.27,20.7,150.0,115.0,8.0,11.0,4.8,2.76,4.48,474.0,244.0,0.52,589.0,128.0,4.78,3.43,5.34,2.49,45.1,27.9,82.4,50.0,'IS808_Rev',4.38); +INSERT INTO UnequalAngle VALUES(53,'∠150 ⅹ 115ⅹ 10',20.14,25.6,150.0,115.0,10.0,11.0,4.8,2.84,4.57,581.0,298.0,0.52,722.0,157.0,4.76,3.41,5.31,2.48,55.8,34.5,101.0,61.9,'IS808_Rev',8.5); +INSERT INTO UnequalAngle VALUES(54,'∠150 ⅹ 115ⅹ 12',23.96,30.5,150.0,115.0,12.0,11.0,4.8,2.92,4.65,684.0,350.0,0.52,849.0,185.0,4.74,3.39,5.28,2.47,66.2,40.8,120.0,73.5,'IS808_Rev',14.5); +INSERT INTO UnequalAngle VALUES(55,'∠150 ⅹ 115ⅹ 16',31.4,40.0,150.0,115.0,16.0,11.0,4.8,3.07,4.81,878.0,446.0,0.52,1080.0,239.0,4.69,3.34,5.21,2.44,86.2,53.0,156.0,96.1,'IS808_Rev',33.9); +INSERT INTO UnequalAngle VALUES(56,'∠200ⅹ 100ⅹ 10',22.93,29.2,200.0,100.0,10.0,12.0,4.8,2.03,6.98,1220.0,214.0,0.26,1300.0,137.0,6.48,2.71,6.68,2.17,94.3,26.9,165.0,48.7,'IS808_Rev',9.66); +INSERT INTO UnequalAngle VALUES(57,'∠200ⅹ 100ⅹ 12',27.29,34.7,200.0,100.0,12.0,12.0,4.8,2.11,7.07,1440.0,251.0,0.26,1530.0,161.0,6.46,2.69,6.65,2.15,112.0,31.9,196.0,58.3,'IS808_Rev',16.5); +INSERT INTO UnequalAngle VALUES(58,'∠200ⅹ 100ⅹ 16',35.84,45.6,200.0,100.0,16.0,12.0,4.8,2.27,7.23,1870.0,319.0,0.25,1980.0,207.0,6.4,2.65,6.59,2.13,146.0,41.3,255.0,77.5,'IS808_Rev',38.7); +INSERT INTO UnequalAngle VALUES(59,'∠200ⅹ 150ⅹ 10',26.92,34.2,200.0,150.0,10.0,13.5,4.8,3.55,6.02,1400.0,688.0,0.51,1720.0,368.0,6.41,4.48,7.1,3.28,100.0,60.2,183.0,107.0,'IS808_Rev',11.3); +INSERT INTO UnequalAngle VALUES(60,'∠200ⅹ 150ⅹ 12',32.07,40.8,200.0,150.0,12.0,13.5,4.8,3.63,6.11,1660.0,812.0,0.51,2040.0,433.0,6.39,4.46,7.07,3.26,119.0,71.4,218.0,127.0,'IS808_Rev',19.4); +INSERT INTO UnequalAngle VALUES(61,'∠200ⅹ 150ⅹ 16',42.18,53.7,200.0,150.0,16.0,13.5,4.8,3.79,6.27,2150.0,1040.0,0.5,2630.0,560.0,6.33,4.41,7.01,3.23,156.0,93.2,285.0,167.0,'IS808_Rev',45.6); +INSERT INTO UnequalAngle VALUES(62,'∠200ⅹ 150ⅹ 20',52.04,66.2,200.0,150.0,20.0,13.5,4.8,3.94,6.42,2610.0,1260.0,0.5,3190.0,682.0,6.28,4.36,6.94,3.21,192.0,114.0,349.0,206.0,'IS808_Rev',88.0); +INSERT INTO UnequalAngle VALUES(63,'∠ 40 ⅹ20ⅹ3',1.37,1.74,40.0,20.0,3.0,4.0,0.0,0.45,1.43,2.9,0.49,0.25,3.04,0.32,1.28,0.53,1.32,0.43,1.11,0.32,1.95,0.59,'IS808_Rev',0.050999999999999996447); +INSERT INTO UnequalAngle VALUES(64,'∠ 40 ⅹ20ⅹ4',1.79,2.27,40.0,20.0,4.0,4.0,0.0,0.49,1.47,3.7,0.62,0.25,3.86,0.41,1.27,0.52,1.3,0.42,1.45,0.41,2.52,0.78,'IS808_Rev',0.11899999999999999467); +INSERT INTO UnequalAngle VALUES(65,'∠ 40 ⅹ20ⅹ5',2.19,2.78,40.0,20.0,5.0,4.0,0.0,0.52,1.51,4.4,0.73,0.24,4.62,0.49,1.25,0.51,1.29,0.42,1.76,0.49,3.05,0.97,'IS808_Rev',0.22900000000000000355); +INSERT INTO UnequalAngle VALUES(66,'∠ 60 ⅹ30ⅹ5',3.4,4.33,60.0,30.0,5.0,6.0,0.0,0.69,2.16,15.9,2.7,0.25,16.8,1.76,1.92,0.79,1.97,0.64,4.14,1.17,7.24,2.21,'IS808_Rev',0.35400000000000000355); +INSERT INTO UnequalAngle VALUES(67,'∠ 60 ⅹ30ⅹ6',4.02,5.12,60.0,30.0,6.0,6.0,0.0,0.73,2.21,18.5,3.11,0.25,19.6,2.06,1.9,0.78,1.96,0.63,4.88,1.37,8.5,2.64,'IS808_Rev',0.60400000000000000355); +INSERT INTO UnequalAngle VALUES(68,'∠ 60 ⅹ40ⅹ7',5.17,6.59,60.0,40.0,7.0,6.0,0.0,1.06,2.05,23.3,8.23,0.4,26.6,4.86,1.88,1.12,2.01,0.86,5.89,2.8,10.5,5.16,'IS808_Rev',1.06); +INSERT INTO UnequalAngle VALUES(69,' ∠65 ⅹ50ⅹ5',4.38,5.58,65.0,50.0,5.0,6.0,0.0,1.26,2.0,23.6,12.2,0.52,29.3,6.48,2.06,1.48,2.29,1.08,5.25,3.27,9.53,5.85,'IS808_Rev',0.4580000000000000071); +INSERT INTO UnequalAngle VALUES(70,'∠65 ⅹ50ⅹ6',5.19,6.62,65.0,50.0,6.0,6.0,0.0,1.3,2.04,27.6,14.2,0.52,34.3,7.59,2.04,1.47,2.28,1.07,6.2,3.85,11.2,6.93,'IS808_Rev',0.78399999999999998578); +INSERT INTO UnequalAngle VALUES(71,'∠65 ⅹ50ⅹ7',6.0,7.64,65.0,50.0,7.0,6.0,0.0,1.34,2.08,31.5,16.2,0.52,39.0,8.67,2.03,1.45,2.26,1.07,7.13,4.42,12.9,7.99,'IS808_Rev',1.23); +INSERT INTO UnequalAngle VALUES(72,'∠65 ⅹ50ⅹ8',6.78,8.64,65.0,50.0,8.0,6.0,0.0,1.38,2.12,35.2,18.0,0.52,43.4,9.72,2.02,1.44,2.24,1.06,8.03,4.97,14.5,9.03,'IS808_Rev',1.82); +INSERT INTO UnequalAngle VALUES(73,'∠ 70ⅹ 50ⅹ5',4.57,5.83,70.0,50.0,5.0,6.0,0.0,1.22,2.21,29.0,12.5,0.46,34.5,6.92,2.23,1.46,2.43,1.09,6.05,3.3,10.9,5.9,'IS808_Rev',0.47900000000000000355); +INSERT INTO UnequalAngle VALUES(74,'∠ 70ⅹ 50ⅹ6',5.43,6.92,70.0,50.0,6.0,6.0,0.0,1.26,2.25,34.0,14.5,0.46,40.4,8.11,2.22,1.45,2.42,1.08,7.16,3.89,12.9,7.0,'IS808_Rev',0.82); +INSERT INTO UnequalAngle VALUES(75,'∠ 70ⅹ 50ⅹ7',6.27,7.99,70.0,50.0,7.0,6.0,0.0,1.3,2.29,38.8,16.5,0.46,46.0,9.26,2.2,1.44,2.4,1.08,8.23,4.46,14.8,8.08,'IS808_Rev',1.29); +INSERT INTO UnequalAngle VALUES(76,'∠ 70ⅹ 50ⅹ8',7.09,9.04,70.0,50.0,8.0,6.0,0.0,1.33,2.33,43.4,18.4,0.46,51.4,10.3,2.19,1.43,2.38,1.07,9.28,5.01,16.7,9.14,'IS808_Rev',1.91); +INSERT INTO UnequalAngle VALUES(77,'∠75 ⅹ50ⅹ7',6.57,8.37,75.0,50.0,7.0,7.0,0.0,1.26,2.49,47.1,16.8,0.41,54.2,9.8,2.37,1.42,2.54,1.08,9.41,4.49,16.9,8.17,'IS808_Rev',1.34); +INSERT INTO UnequalAngle VALUES(78,'∠80 ⅹ40ⅹ5',4.6,5.86,80.0,40.0,5.0,7.0,0.0,0.86,2.82,39.0,6.74,0.26,41.4,4.36,2.58,1.07,2.66,0.86,7.53,2.14,13.1,3.94,'IS808_Rev',0.47900000000000000355); +INSERT INTO UnequalAngle VALUES(79,'∠80 ⅹ40ⅹ6',5.45,6.95,80.0,40.0,6.0,7.0,0.0,0.89,2.86,45.7,7.84,0.25,48.5,5.09,2.57,1.06,2.64,0.86,8.9,2.52,15.5,4.7,'IS808_Rev',0.82); +INSERT INTO UnequalAngle VALUES(80,'∠80 ⅹ40ⅹ7',6.29,8.02,80.0,40.0,7.0,7.0,0.0,0.93,2.91,52.2,8.87,0.25,55.3,5.8,2.55,1.05,2.63,0.85,10.2,2.89,17.8,5.47,'IS808_Rev',1.29); +INSERT INTO UnequalAngle VALUES(81,'∠80 ⅹ40ⅹ8',7.12,9.07,80.0,40.0,8.0,7.0,0.0,0.97,2.95,58.4,9.84,0.25,61.7,6.5,2.54,1.04,2.61,0.85,11.5,3.25,20.1,6.24,'IS808_Rev',1.91); +INSERT INTO UnequalAngle VALUES(82,'∠ 80ⅹ 60ⅹ6',6.42,8.18,80.0,60.0,6.0,8.0,0.0,1.5,2.48,52.6,25.5,0.5,64.3,13.8,2.54,1.77,2.8,1.3,9.5,5.7,17.3,10.1,'IS808_Rev',0.96400000000000005684); +INSERT INTO UnequalAngle VALUES(83,'∠ 80ⅹ 60ⅹ7',7.42,9.45,80.0,60.0,7.0,8.0,0.0,1.54,2.52,60.1,29.1,0.5,73.4,15.8,2.52,1.75,2.79,1.29,11.0,6.5,19.9,11.7,'IS808_Rev',1.52); +INSERT INTO UnequalAngle VALUES(84,'∠ 80ⅹ 60ⅹ8',8.4,10.7,80.0,60.0,8.0,8.0,0.0,1.57,2.56,67.4,32.5,0.5,82.2,17.7,2.51,1.74,2.77,1.29,12.4,7.3,22.4,13.3,'IS808_Rev',2.25); +INSERT INTO UnequalAngle VALUES(85,'∠ 90ⅹ 65 ⅹ 6',7.13,9.08,90.0,65.0,6.0,8.0,0.0,1.57,2.81,74.8,33.1,0.47,89.7,18.3,2.87,1.91,3.14,1.42,12.1,6.7,21.9,12.0,'IS808_Rev',1.07); +INSERT INTO UnequalAngle VALUES(86,'∠ 90ⅹ 65 ⅹ7',8.24,10.5,90.0,65.0,7.0,8.0,0.0,1.61,2.85,85.7,37.8,0.47,102.0,20.9,2.86,1.9,3.13,1.41,13.9,7.7,25.2,13.9,'IS808_Rev',1.69); +INSERT INTO UnequalAngle VALUES(87,'∠ 90ⅹ 65 ⅹ8',9.34,11.9,90.0,65.0,8.0,8.0,0.0,1.65,2.89,96.3,42.3,0.47,115.0,23.5,2.84,1.89,3.11,1.4,15.8,8.7,28.5,15.7,'IS808_Rev',2.5); +INSERT INTO UnequalAngle VALUES(88,'∠ 90ⅹ 65 ⅹ10',11.49,14.6,90.0,65.0,10.0,8.0,0.0,1.73,2.97,116.0,50.7,0.47,138.0,28.4,2.82,1.86,3.08,1.39,19.3,10.6,34.8,19.3,'IS808_Rev',4.83); +INSERT INTO UnequalAngle VALUES(89,'∠100 ⅹ50 ⅹ 6',6.92,8.81,100.0,50.0,6.0,9.0,0.0,1.06,3.51,91.9,15.9,0.26,97.5,10.3,3.23,1.34,3.33,1.08,14.2,4.0,24.8,7.4,'IS808_Rev',1.03); +INSERT INTO UnequalAngle VALUES(90,'∠100 ⅹ50 ⅹ 7',7.99,10.1,100.0,50.0,7.0,9.0,0.0,1.1,3.56,105.0,18.1,0.26,111.0,11.7,3.21,1.33,3.31,1.07,16.3,4.6,28.6,8.6,'IS808_Rev',1.63); +INSERT INTO UnequalAngle VALUES(91,'∠100 ⅹ50 ⅹ 8',9.05,11.5,100.0,50.0,8.0,9.0,0.0,1.14,3.6,118.0,20.2,0.25,125.0,13.1,3.2,1.32,3.29,1.07,18.5,5.2,32.2,9.8,'IS808_Rev',2.42); +INSERT INTO UnequalAngle VALUES(92,'∠100 ⅹ50 ⅹ10',11.13,14.1,100.0,50.0,10.0,9.0,0.0,1.21,3.68,142.0,24.0,0.25,150.0,15.9,3.17,1.3,3.26,1.06,22.6,6.3,39.3,12.2,'IS808_Rev',4.66); +INSERT INTO UnequalAngle VALUES(93,'∠100 ⅹ65 ⅹ7',8.85,11.2,100.0,65.0,7.0,10.0,0.0,1.53,3.25,115.0,38.9,0.4,131.0,22.8,3.2,1.86,3.41,1.42,17.1,7.8,30.7,14.1,'IS808_Rev',1.8); +INSERT INTO UnequalAngle VALUES(94,'∠120ⅹ80 ⅹ8',12.26,15.6,120.0,80.0,8.0,11.0,0.0,1.89,3.85,230.0,83.2,0.41,265.0,48.1,3.84,2.31,4.12,1.75,28.3,13.6,51.0,24.4,'IS808_Rev',3.27); +INSERT INTO UnequalAngle VALUES(95,'∠120ⅹ80 ⅹ10',15.12,19.2,120.0,80.0,10.0,11.0,0.0,1.96,3.94,280.0,100.0,0.41,322.0,58.3,3.81,2.28,4.09,1.74,34.8,16.6,62.6,30.1,'IS808_Rev',6.33); +INSERT INTO UnequalAngle VALUES(96,'∠120ⅹ80 ⅹ12',17.91,22.8,120.0,80.0,12.0,11.0,0.0,2.04,4.02,327.0,116.0,0.41,375.0,68.1,3.79,2.26,4.06,1.73,41.0,19.6,73.7,35.7,'IS808_Rev',10.8); +INSERT INTO UnequalAngle VALUES(97,'∠125ⅹ75 ⅹ12',17.91,22.8,125.0,75.0,12.0,11.0,0.0,1.85,4.32,358.0,97.5,0.34,396.0,59.8,3.97,2.07,4.17,1.62,43.9,17.3,78.1,31.8,'IS808_Rev',10.8); +INSERT INTO UnequalAngle VALUES(98,'∠135ⅹ65 ⅹ8',12.18,15.5,135.0,65.0,8.0,11.0,4.8,1.35,4.79,292.0,45.5,0.24,308.0,29.7,4.34,1.71,4.46,1.38,33.6,8.8,59.0,16.4,'IS808_Rev',3.27); +INSERT INTO UnequalAngle VALUES(99,'∠135ⅹ65 ⅹ10',15.04,19.1,135.0,65.0,10.0,11.0,4.8,1.43,4.88,357.0,55.0,0.24,376.0,36.1,4.32,1.69,4.43,1.37,41.4,10.8,72.5,20.5,'IS808_Rev',6.33); +INSERT INTO UnequalAngle VALUES(100,'∠135ⅹ65 ⅹ12',17.84,22.7,135.0,65.0,12.0,11.0,4.8,1.51,4.97,418.0,63.9,0.24,440.0,42.3,4.29,1.68,4.4,1.36,49.0,12.8,85.4,24.6,'IS808_Rev',10.8); +INSERT INTO UnequalAngle VALUES(101,'∠150ⅹ75 ⅹ9',15.39,19.6,150.0,75.0,9.0,11.0,4.8,1.58,5.28,457.0,78.8,0.26,485.0,50.7,4.83,2.01,4.98,1.61,47.1,13.3,82.8,24.5,'IS808_Rev',5.24); +INSERT INTO UnequalAngle VALUES(102,'∠150ⅹ75 ⅹ15',24.85,31.6,150.0,75.0,15.0,11.0,4.8,1.81,5.53,715.0,120.0,0.25,755.0,79.1,4.75,1.95,4.89,1.58,75.5,21.1,131.0,40.7,'IS808_Rev',23.6); +INSERT INTO UnequalAngle VALUES(103,'∠150ⅹ90ⅹ10',18.22,23.2,150.0,90.0,10.0,12.0,4.8,2.04,5.0,536.0,147.0,0.35,594.0,89.1,4.81,2.52,5.06,1.96,53.6,21.2,96.2,38.4,'IS808_Rev',7.66); +INSERT INTO UnequalAngle VALUES(104,'∠150ⅹ90ⅹ12',21.64,27.5,150.0,90.0,12.0,12.0,4.8,2.12,5.09,630.0,172.0,0.34,698.0,104.0,4.78,2.5,5.03,1.95,63.6,25.0,113.0,45.8,'IS808_Rev',13.1); +INSERT INTO UnequalAngle VALUES(105,'∠150ⅹ90ⅹ15',26.66,33.9,150.0,90.0,15.0,12.0,4.8,2.24,5.21,764.0,206.0,0.34,843.0,126.0,4.74,2.47,4.98,1.93,78.0,30.6,139.0,56.7,'IS808_Rev',25.3); +INSERT INTO UnequalAngle VALUES(106,'∠200ⅹ100ⅹ15',33.86,43.1,200.0,100.0,15.0,15.0,4.8,2.23,7.17,1770.0,303.0,0.25,1870.0,196.0,6.41,2.65,6.6,2.13,138.0,39.0,241.0,72.9,'IS808_Rev',32.0); +INSERT INTO UnequalAngle VALUES(107,'∠200ⅹ150ⅹ15',39.75,50.6,200.0,150.0,15.0,15.0,4.8,3.75,6.22,2030.0,988.0,0.5,2490.0,530.0,6.34,4.42,7.02,3.24,147.0,87.8,268.0,157.0,'IS808_Rev',37.6); +INSERT INTO UnequalAngle VALUES(108,'∠200ⅹ150ⅹ18',47.21,60.1,200.0,150.0,18.0,15.0,4.8,3.86,6.34,2390.0,1150.0,0.5,2920.0,623.0,6.3,4.38,6.97,3.22,175.0,103.0,317.0,187.0,'IS808_Rev',64.5); +CREATE TABLE IF NOT EXISTS "EqualAngle" ( + "Id" INTEGER NOT NULL, + "Designation" VARCHAR(50), + "Mass" REAL(10 , 2), + "Area" REAL(10 , 2), + "a" REAL(10 , 2), + "b" REAL(10 , 2), + "t" REAL(10 , 2), + "R1" REAL(10 , 2), + "R2" REAL(10 , 2), + "Cz" REAL(10 , 2), + "Cy" REAL(10 , 2), + "Iz" REAL(10 , 2), + "Iy" REAL(10 , 2), + "Alpha" REAL(10 , 2), + "Iu(max)" REAL(10 , 2), + "Iv(min)" REAL(10 , 2), + "rz" REAL(10 , 2), + "ry" REAL(10 , 2), + "ru(max)" REAL(10 , 2), + "rv(min)" REAL(10 , 2), + "Zz" REAL(10 , 2), + "Zy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "Source" VARCHAR(50), + "It" REAL(10 , 2), + PRIMARY KEY("Id") +); +INSERT INTO EqualAngle VALUES(1,'∠ 20ⅹ 20ⅹ 3',0.9,1.14,20.0,20.0,3.0,4.0,0.0,0.6,0.6,0.4,0.4,0.79,0.64,0.17,0.59,0.59,0.75,0.39,0.29,0.29,0.52,0.53,'IS808_Rev',0.033000000000000007105); +INSERT INTO EqualAngle VALUES(2,'∠ 20ⅹ 20ⅹ 4',1.16,1.47,20.0,20.0,4.0,4.0,0.0,0.64,0.64,0.5,0.5,0.79,0.79,0.22,0.58,0.58,0.73,0.39,0.37,0.37,0.66,0.67,'IS808_Rev',0.075999999999999996447); +INSERT INTO EqualAngle VALUES(3,'∠ 25ⅹ 25ⅹ 3',1.14,1.45,25.0,25.0,3.0,4.5,0.0,0.73,0.73,0.83,0.83,0.79,1.3,0.35,0.75,0.75,0.95,0.49,0.46,0.46,0.83,0.84,'IS808_Rev',0.042000000000000001776); +INSERT INTO EqualAngle VALUES(4,'∠ 25ⅹ 25ⅹ 4',1.48,1.88,25.0,25.0,4.0,4.5,0.0,0.76,0.76,1.04,1.04,0.79,1.63,0.44,0.74,0.74,0.93,0.48,0.6,0.6,1.07,1.09,'IS808_Rev',0.098000000000000024868); +INSERT INTO EqualAngle VALUES(5,'∠ 25ⅹ 25ⅹ 5',1.8,2.29,25.0,25.0,5.0,4.5,0.0,0.8,0.8,1.23,1.23,0.79,1.92,0.54,0.73,0.73,0.92,0.48,0.72,0.72,1.3,1.31,'IS808_Rev',0.18700000000000001065); +INSERT INTO EqualAngle VALUES(6,'∠ 30ⅹ 30ⅹ 3',1.38,1.76,30.0,30.0,3.0,5.0,0.0,0.85,0.85,1.47,1.47,0.79,2.32,0.62,0.91,0.91,1.15,0.59,0.68,0.68,1.22,1.23,'IS808_Rev',0.050999999999999996447); +INSERT INTO EqualAngle VALUES(7,'∠ 30ⅹ 30ⅹ 4',1.8,2.29,30.0,30.0,4.0,5.0,0.0,0.89,0.89,1.86,1.86,0.79,2.94,0.78,0.9,0.9,1.13,0.58,0.88,0.88,1.58,1.6,'IS808_Rev',0.11899999999999999467); +INSERT INTO EqualAngle VALUES(8,'∠ 30ⅹ 30ⅹ 5',2.2,2.8,30.0,30.0,5.0,5.0,0.0,0.93,0.93,2.22,2.22,0.79,3.49,0.95,0.89,0.89,1.12,0.58,1.07,1.07,1.92,1.94,'IS808_Rev',0.22900000000000000355); +INSERT INTO EqualAngle VALUES(9,'∠ 35ⅹ 35ⅹ 3',1.62,2.06,35.0,35.0,3.0,5.0,0.0,0.97,0.97,2.38,2.38,0.79,3.77,0.99,1.07,1.07,1.35,0.69,0.94,0.94,1.69,1.7,'IS808_Rev',0.06); +INSERT INTO EqualAngle VALUES(10,'∠ 35ⅹ 35ⅹ 4',2.11,2.69,35.0,35.0,4.0,5.0,0.0,1.01,1.01,3.04,3.04,0.79,4.81,1.27,1.06,1.06,1.34,0.69,1.22,1.22,2.19,2.21,'IS808_Rev',0.14); +INSERT INTO EqualAngle VALUES(11,'∠ 35ⅹ 35ⅹ 5',2.59,3.3,35.0,35.0,5.0,5.0,0.0,1.05,1.05,3.65,3.65,0.79,5.76,1.54,1.05,1.05,1.32,0.68,1.49,1.49,2.68,2.69,'IS808_Rev',0.27); +INSERT INTO EqualAngle VALUES(12,'∠ 35ⅹ 35ⅹ 6',3.06,3.89,35.0,35.0,6.0,5.0,0.0,1.09,1.09,4.2,4.2,0.79,6.61,1.8,1.04,1.04,1.3,0.68,1.74,1.74,3.14,3.15,'IS808_Rev',0.46); +INSERT INTO EqualAngle VALUES(13,'∠ 40ⅹ 40ⅹ 3',1.86,2.37,40.0,40.0,3.0,5.5,0.0,1.09,1.09,3.61,3.61,0.79,5.72,1.51,1.23,1.23,1.55,0.8,1.24,1.24,2.22,2.24,'IS808_Rev',0.069000000000000003552); +INSERT INTO EqualAngle VALUES(14,'∠ 40ⅹ 40ⅹ 4',2.44,3.1,40.0,40.0,4.0,5.5,0.0,1.13,1.13,4.63,4.63,0.79,7.34,1.93,1.22,1.22,1.54,0.79,1.62,1.62,2.9,2.92,'IS808_Rev',0.16200000000000001065); +INSERT INTO EqualAngle VALUES(15,'∠ 40ⅹ 40ⅹ 5',2.99,3.81,40.0,40.0,5.0,5.5,0.0,1.17,1.17,5.58,5.58,0.79,8.83,2.33,1.21,1.21,1.52,0.78,1.97,1.97,3.55,3.57,'IS808_Rev',0.31200000000000001065); +INSERT INTO EqualAngle VALUES(16,'∠ 40ⅹ 40ⅹ 6',3.54,4.5,40.0,40.0,6.0,5.5,0.0,1.21,1.21,6.46,6.46,0.79,10.2,2.73,1.2,1.2,1.5,0.78,2.32,2.32,4.17,4.19,'IS808_Rev',0.53200000000000002842); +INSERT INTO EqualAngle VALUES(17,'∠ 45ⅹ 45ⅹ 3',2.1,2.67,45.0,45.0,3.0,5.5,0.0,1.22,1.22,5.2,5.2,0.79,8.2,2.17,1.39,1.39,1.76,0.9,1.58,1.58,2.84,2.86,'IS808_Rev',0.078000000000000015987); +INSERT INTO EqualAngle VALUES(18,'∠ 45ⅹ 45ⅹ 4',2.75,3.5,45.0,45.0,4.0,5.5,0.0,1.26,1.26,6.7,6.7,0.79,10.6,2.78,1.38,1.38,1.74,0.89,2.07,2.07,3.71,3.73,'IS808_Rev',0.1830000000000000071); +INSERT INTO EqualAngle VALUES(19,'∠ 45ⅹ 45ⅹ 5',3.39,4.31,45.0,45.0,5.0,5.5,0.0,1.3,1.3,8.1,8.1,0.79,12.8,3.37,1.37,1.37,1.72,0.88,2.53,2.53,4.55,4.57,'IS808_Rev',0.35400000000000000355); +INSERT INTO EqualAngle VALUES(20,'∠ 45ⅹ 45ⅹ 6',4.01,5.1,45.0,45.0,6.0,5.5,0.0,1.34,1.34,9.42,9.42,0.79,14.9,3.94,1.36,1.36,1.71,0.88,2.98,2.98,5.36,5.38,'IS808_Rev',0.60400000000000000355); +INSERT INTO EqualAngle VALUES(21,'∠ 50ⅹ 50ⅹ 3',2.34,2.99,50.0,50.0,3.0,6.0,0.0,1.34,1.34,7.21,7.21,0.79,11.4,3.01,1.55,1.55,1.96,1.0,1.97,1.97,3.53,3.55,'IS808_Rev',0.086999999999999992894); +INSERT INTO EqualAngle VALUES(22,'∠ 50ⅹ 50ⅹ 4',3.08,3.92,50.0,50.0,4.0,6.0,0.0,1.38,1.38,9.32,9.32,0.79,14.8,3.86,1.54,1.54,1.94,0.99,2.57,2.57,4.62,4.64,'IS808_Rev',0.20400000000000000355); +INSERT INTO EqualAngle VALUES(23,'∠ 50ⅹ 50ⅹ 5',3.79,4.83,50.0,50.0,5.0,6.0,0.0,1.42,1.42,11.3,11.3,0.79,17.9,4.69,1.53,1.53,1.93,0.99,3.16,3.16,5.67,5.7,'IS808_Rev',0.39500000000000001776); +INSERT INTO EqualAngle VALUES(24,'∠ 50ⅹ 50ⅹ 6',4.49,5.72,50.0,50.0,6.0,6.0,0.0,1.46,1.46,13.2,13.2,0.79,20.8,5.48,1.52,1.52,1.91,0.98,3.72,3.72,6.69,6.71,'IS808_Rev',0.67600000000000015631); +INSERT INTO EqualAngle VALUES(25,'∠ 55ⅹ 55ⅹ 4',3.4,4.33,55.0,55.0,4.0,6.5,0.0,1.5,1.5,12.5,12.5,0.79,19.9,5.2,1.7,1.7,2.14,1.1,3.14,3.14,5.63,5.66,'IS808_Rev',0.22600000000000002309); +INSERT INTO EqualAngle VALUES(26,'∠ 55ⅹ 55ⅹ 5',4.19,5.34,55.0,55.0,5.0,6.5,0.0,1.54,1.54,15.2,15.2,0.79,24.2,6.31,1.69,1.69,2.13,1.09,3.85,3.85,6.92,6.95,'IS808_Rev',0.43700000000000001065); +INSERT INTO EqualAngle VALUES(27,'∠ 55ⅹ 55ⅹ 6',4.97,6.33,55.0,55.0,6.0,6.5,0.0,1.58,1.58,17.8,17.8,0.79,28.2,7.39,1.68,1.68,2.11,1.08,4.55,4.55,8.17,8.2,'IS808_Rev',0.74800000000000004263); +INSERT INTO EqualAngle VALUES(28,'∠ 55ⅹ 55ⅹ 8',6.48,8.25,55.0,55.0,8.0,6.5,0.0,1.66,1.66,22.5,22.5,0.79,35.6,9.48,1.65,1.65,2.08,1.07,5.87,5.87,10.5,10.6,'IS808_Rev',1.74); +INSERT INTO EqualAngle VALUES(29,'∠ 60ⅹ 60ⅹ 4',3.71,4.73,60.0,60.0,4.0,6.5,0.0,1.63,1.63,16.4,16.4,0.79,26.0,6.8,1.86,1.86,2.35,1.2,3.76,3.76,6.74,6.77,'IS808_Rev',0.24699999999999993072); +INSERT INTO EqualAngle VALUES(30,'∠ 60ⅹ 60ⅹ 5',4.58,5.84,60.0,60.0,5.0,6.5,0.0,1.67,1.67,20.0,20.0,0.79,31.7,8.26,1.85,1.85,2.33,1.19,4.62,4.62,8.3,8.32,'IS808_Rev',0.47900000000000000355); +INSERT INTO EqualAngle VALUES(31,'∠ 60ⅹ 60ⅹ 6',5.44,6.93,60.0,60.0,6.0,6.5,0.0,1.71,1.71,23.4,23.4,0.79,37.1,9.69,1.84,1.84,2.31,1.18,5.46,5.46,9.81,9.84,'IS808_Rev',0.82); +INSERT INTO EqualAngle VALUES(32,'∠ 60ⅹ 60ⅹ 8',7.1,9.05,60.0,60.0,8.0,6.5,0.0,1.78,1.78,29.8,29.8,0.79,47.1,12.4,1.81,1.81,2.28,1.17,7.06,7.06,12.7,12.7,'IS808_Rev',1.91); +INSERT INTO EqualAngle VALUES(33,'∠ 65ⅹ 65ⅹ 4',4.03,5.13,65.0,65.0,4.0,6.5,0.0,1.75,1.75,21.0,21.0,0.79,33.4,8.69,2.02,2.02,2.55,1.3,4.43,4.43,7.95,7.98,'IS808_Rev',0.26800000000000001598); +INSERT INTO EqualAngle VALUES(34,'∠ 65ⅹ 65ⅹ 5',4.98,6.34,65.0,65.0,5.0,6.5,0.0,1.79,1.79,25.7,25.7,0.79,40.8,10.6,2.01,2.01,2.54,1.29,5.45,5.45,9.8,9.83,'IS808_Rev',0.52); +INSERT INTO EqualAngle VALUES(35,'∠ 65ⅹ 65ⅹ 6',5.91,7.53,65.0,65.0,6.0,6.5,0.0,1.83,1.83,30.1,30.1,0.79,47.8,12.4,2.0,2.0,2.52,1.28,6.45,6.45,11.5,11.6,'IS808_Rev',0.89199999999999999289); +INSERT INTO EqualAngle VALUES(36,'∠ 65ⅹ 65ⅹ 8',7.73,9.85,65.0,65.0,8.0,6.5,0.0,1.91,1.91,38.4,38.4,0.79,60.8,16.0,1.97,1.97,2.48,1.27,8.36,8.36,15.0,15.0,'IS808_Rev',2.08); +INSERT INTO EqualAngle VALUES(37,'∠ 70ⅹ 70ⅹ 5',5.38,6.86,70.0,70.0,5.0,7.0,0.0,1.92,1.92,32.3,32.3,0.79,51.3,13.3,2.17,2.17,2.74,1.39,6.36,6.36,11.4,11.4,'IS808_Rev',0.56200000000000009947); +INSERT INTO EqualAngle VALUES(38,'∠ 70ⅹ 70ⅹ 6',6.39,8.15,70.0,70.0,6.0,7.0,0.0,1.96,1.96,38.0,38.0,0.79,60.3,15.6,2.16,2.16,2.72,1.39,7.53,7.53,13.5,13.5,'IS808_Rev',0.96400000000000005684); +INSERT INTO EqualAngle VALUES(39,'∠ 70ⅹ 70ⅹ 8',8.37,10.6,70.0,70.0,8.0,7.0,0.0,2.03,2.03,48.5,48.5,0.79,76.9,20.1,2.13,2.13,2.69,1.37,9.77,9.77,17.5,17.6,'IS808_Rev',2.25); +INSERT INTO EqualAngle VALUES(40,'∠ 70ⅹ 70ⅹ 10',10.29,13.1,70.0,70.0,10.0,7.0,0.0,2.11,2.11,58.3,58.3,0.79,92.1,24.4,2.11,2.11,2.65,1.37,11.9,11.9,21.4,21.5,'IS808_Rev',4.33); +INSERT INTO EqualAngle VALUES(41,'∠ 75ⅹ 75ⅹ 5',5.77,7.36,75.0,75.0,5.0,7.0,0.0,2.04,2.04,40.0,40.0,0.79,63.6,16.5,2.33,2.33,2.94,1.5,7.3,7.3,13.2,13.2,'IS808_Rev',0.60400000000000000355); +INSERT INTO EqualAngle VALUES(42,'∠ 75ⅹ 75ⅹ 6',6.86,8.75,75.0,75.0,6.0,7.0,0.0,2.08,2.08,47.1,47.1,0.79,74.8,19.4,2.32,2.32,2.92,1.49,8.7,8.7,15.6,15.6,'IS808_Rev',1.03); +INSERT INTO EqualAngle VALUES(43,'∠ 75ⅹ 75ⅹ 8',9.0,11.4,75.0,75.0,8.0,7.0,0.0,2.16,2.16,60.3,60.3,0.79,95.7,24.9,2.29,2.29,2.89,1.47,11.3,11.3,20.3,20.4,'IS808_Rev',2.42); +INSERT INTO EqualAngle VALUES(44,'∠ 75ⅹ 75ⅹ 10',11.07,14.1,75.0,75.0,10.0,7.0,0.0,2.23,2.23,72.6,72.6,0.79,114.0,30.3,2.27,2.27,2.85,1.47,13.8,13.8,24.8,24.9,'IS808_Rev',4.66); +INSERT INTO EqualAngle VALUES(45,'∠ 80ⅹ 80ⅹ 6',7.36,9.38,80.0,80.0,6.0,8.0,0.0,2.2,2.2,57.6,57.6,0.79,91.4,23.7,2.48,2.48,3.12,1.59,9.9,9.9,17.8,17.9,'IS808_Rev',1.1); +INSERT INTO EqualAngle VALUES(46,'∠ 80ⅹ 80ⅹ 8',9.65,12.3,80.0,80.0,8.0,8.0,0.0,2.28,2.28,74.0,74.0,0.79,117.0,30.5,2.45,2.45,3.09,1.58,12.9,12.9,23.3,23.3,'IS808_Rev',2.59); +INSERT INTO EqualAngle VALUES(47,'∠ 80ⅹ 80ⅹ 10',11.88,15.1,80.0,80.0,10.0,8.0,0.0,2.36,2.36,89.2,89.2,0.79,141.0,37.1,2.43,2.43,3.05,1.57,15.8,15.8,28.4,28.5,'IS808_Rev',5.0); +INSERT INTO EqualAngle VALUES(48,'∠ 80ⅹ 80ⅹ 12',14.05,17.9,80.0,80.0,12.0,8.0,0.0,2.43,2.43,103.0,103.0,0.79,163.0,43.5,2.4,2.4,3.02,1.56,18.5,18.5,33.4,33.5,'IS808_Rev',8.52); +INSERT INTO EqualAngle VALUES(49,'∠ 90ⅹ 90ⅹ 6',8.32,10.6,90.0,90.0,6.0,8.5,0.0,2.45,2.45,83.0,83.0,0.79,131.0,34.2,2.8,2.8,3.53,1.8,12.7,12.7,22.8,22.8,'IS808_Rev',1.25); +INSERT INTO EqualAngle VALUES(50,'∠ 90ⅹ 90ⅹ 8',10.92,13.9,90.0,90.0,8.0,8.5,0.0,2.53,2.53,107.0,107.0,0.79,170.0,44.1,2.77,2.77,3.5,1.78,16.5,16.5,29.7,29.8,'IS808_Rev',2.93); +INSERT INTO EqualAngle VALUES(51,'∠ 90ⅹ 90ⅹ 10',13.47,17.1,90.0,90.0,10.0,8.5,0.0,2.6,2.6,129.0,129.0,0.79,205.0,53.6,2.75,2.75,3.46,1.77,20.2,20.2,36.4,36.5,'IS808_Rev',5.66); +INSERT INTO EqualAngle VALUES(52,'∠ 90ⅹ 90ⅹ 12',15.95,20.3,90.0,90.0,12.0,8.5,0.0,2.68,2.68,150.0,150.0,0.79,238.0,62.8,2.72,2.72,3.42,1.76,23.8,23.8,42.9,43.0,'IS808_Rev',9.67); +INSERT INTO EqualAngle VALUES(53,'∠ 100 ⅹ 100ⅹ 6',9.26,11.8,100.0,100.0,6.0,8.5,0.0,2.7,2.7,115.0,115.0,0.79,182.0,47.2,3.12,3.12,3.94,2.0,15.7,15.7,28.3,28.3,'IS808_Rev',1.39); +INSERT INTO EqualAngle VALUES(54,'∠ 100 ⅹ 100ⅹ 8',12.18,15.5,100.0,100.0,8.0,8.5,0.0,2.78,2.78,148.0,148.0,0.79,236.0,61.0,3.1,3.1,3.9,1.98,20.6,20.6,37.0,37.1,'IS808_Rev',3.27); +INSERT INTO EqualAngle VALUES(55,'∠ 100 ⅹ 100ⅹ 10',15.04,19.1,100.0,100.0,10.0,8.5,0.0,2.85,2.85,180.0,180.0,0.79,286.0,74.3,3.07,3.07,3.87,1.97,25.3,25.3,45.4,45.5,'IS808_Rev',6.33); +INSERT INTO EqualAngle VALUES(56,'∠ 100 ⅹ 100ⅹ 12',17.83,22.7,100.0,100.0,12.0,8.5,0.0,2.93,2.93,210.0,210.0,0.79,333.0,87.2,3.04,3.04,3.83,1.96,29.8,29.8,53.6,53.7,'IS808_Rev',10.8); +INSERT INTO EqualAngle VALUES(57,'∠ 110 ⅹ 110ⅹ 8',13.4,17.0,110.0,110.0,8.0,10.0,4.8,3.0,3.0,196.0,196.0,0.79,312.0,80.7,3.39,3.39,4.28,2.17,24.6,24.6,44.6,44.7,'IS808_Rev',3.61); +INSERT INTO EqualAngle VALUES(58,'∠ 110 ⅹ 110ⅹ 10',16.58,21.1,110.0,110.0,10.0,10.0,4.8,3.09,3.09,240.0,240.0,0.79,381.0,98.6,3.37,3.37,4.25,2.16,30.4,30.4,54.9,55.0,'IS808_Rev',7.0); +INSERT INTO EqualAngle VALUES(59,'∠ 110 ⅹ 110ⅹ 12',19.68,25.0,110.0,110.0,12.0,10.0,4.8,3.17,3.17,281.0,281.0,0.79,446.0,116.0,3.35,3.35,4.22,2.15,35.9,35.9,64.9,65.1,'IS808_Rev',11.9); +INSERT INTO EqualAngle VALUES(60,'∠ 110 ⅹ 110ⅹ 16',25.71,32.7,110.0,110.0,16.0,10.0,4.8,3.32,3.32,357.0,357.0,0.79,565.0,149.0,3.3,3.3,4.15,2.14,46.5,46.5,84.1,84.2,'IS808_Rev',27.8); +INSERT INTO EqualAngle VALUES(61,'∠ 130ⅹ 130ⅹ 8',15.92,20.2,130.0,130.0,8.0,10.0,4.8,3.5,3.5,330.0,330.0,0.79,526.0,135.0,4.04,4.04,5.1,2.58,34.8,34.8,63.0,63.1,'IS808_Rev',4.3); +INSERT INTO EqualAngle VALUES(62,'∠ 130ⅹ130ⅹ 10',19.72,25.1,130.0,130.0,10.0,10.0,4.8,3.59,3.59,405.0,405.0,0.79,644.0,165.0,4.02,4.02,5.07,2.57,43.1,43.1,77.8,77.9,'IS808_Rev',8.33); +INSERT INTO EqualAngle VALUES(63,'∠ 130ⅹ130ⅹ 12',23.45,29.8,130.0,130.0,12.0,10.0,4.8,3.67,3.67,476.0,476.0,0.79,757.0,195.0,3.99,3.99,5.04,2.56,51.0,51.0,92.2,92.3,'IS808_Rev',14.2); +INSERT INTO EqualAngle VALUES(64,'∠ 130ⅹ130ⅹ 16',30.74,39.1,130.0,130.0,16.0,10.0,4.8,3.82,3.82,609.0,609.0,0.79,966.0,252.0,3.94,3.94,4.97,2.54,66.3,66.3,119.0,120.0,'IS808_Rev',33.3); +INSERT INTO EqualAngle VALUES(65,'∠150ⅹ 150ⅹ 10',22.93,29.2,150.0,150.0,10.0,12.0,4.8,4.08,4.08,633.0,633.0,0.79,1000.0,259.0,4.66,4.66,5.87,2.98,58.0,58.0,104.0,104.0,'IS808_Rev',9.66); +INSERT INTO EqualAngle VALUES(66,'∠150ⅹ 150ⅹ 12',27.29,34.7,150.0,150.0,12.0,12.0,4.8,4.16,4.16,746.0,746.0,0.79,1180.0,305.0,4.63,4.63,5.84,2.96,68.8,68.8,124.0,124.0,'IS808_Rev',16.5); +INSERT INTO EqualAngle VALUES(67,'∠150ⅹ 150ⅹ 16',35.84,45.6,150.0,150.0,16.0,12.0,4.8,4.31,4.31,958.0,958.0,0.79,1520.0,394.0,4.58,4.58,5.78,2.94,89.7,89.7,162.0,162.0,'IS808_Rev',38.7); +INSERT INTO EqualAngle VALUES(68,'∠150ⅹ 150ⅹ 20',44.12,56.2,150.0,150.0,20.0,12.0,4.8,4.46,4.46,1150.0,1150.0,0.79,1830.0,480.0,4.53,4.53,5.71,2.92,109.0,109.0,198.0,198.0,'IS808_Rev',74.6); +INSERT INTO EqualAngle VALUES(69,'∠200 ⅹ 200ⅹ 12',36.85,46.9,200.0,200.0,12.0,15.0,4.8,5.39,5.39,1820.0,1820.0,0.79,2900.0,746.0,6.24,6.24,7.87,3.99,125.0,125.0,225.0,225.0,'IS808_Rev',22.3); +INSERT INTO EqualAngle VALUES(70,'∠200 ⅹ 200ⅹ 16',48.53,61.8,200.0,200.0,16.0,15.0,4.8,5.56,5.56,2360.0,2360.0,0.79,3760.0,967.0,6.19,6.19,7.8,3.96,163.0,163.0,295.0,295.0,'IS808_Rev',52.4); +INSERT INTO EqualAngle VALUES(71,'∠200 ⅹ 200ⅹ 20',59.96,76.3,200.0,200.0,20.0,15.0,4.8,5.71,5.71,2870.0,2870.0,0.79,4560.0,1180.0,6.13,6.13,7.73,3.93,201.0,201.0,362.0,363.0,'IS808_Rev',101.0); +INSERT INTO EqualAngle VALUES(72,'∠200 ⅹ 200ⅹ 25',73.9,94.1,200.0,200.0,25.0,15.0,4.8,5.9,5.9,3470.0,3470.0,0.79,5500.0,1430.0,6.07,6.07,7.65,3.91,246.0,246.0,443.0,444.0,'IS808_Rev',195.0); +INSERT INTO EqualAngle VALUES(73,'∠50 ⅹ 50ⅹ 7',5.17,6.59,50.0,50.0,7.0,6.0,0.0,1.5,1.5,14.9,14.9,0.79,23.6,6.27,1.51,1.51,1.89,0.98,4.26,4.26,7.67,7.7,'IS808_Rev',1.06); +INSERT INTO EqualAngle VALUES(74,'∠50 ⅹ 50ⅹ 8',5.84,7.44,50.0,50.0,8.0,6.0,0.0,1.54,1.54,16.6,16.6,0.79,26.2,7.03,1.49,1.49,1.88,0.97,4.79,4.79,8.62,8.65,'IS808_Rev',1.57); +INSERT INTO EqualAngle VALUES(75,'∠55 ⅹ 55 x10',7.92,10.0,55.0,55.0,10.0,6.5,0.0,1.73,1.73,26.8,26.8,0.79,42.1,11.5,1.63,1.63,2.04,1.07,7.11,7.11,12.8,12.8,'IS808_Rev',3.33); +INSERT INTO EqualAngle VALUES(76,'∠60 ⅹ 60 ⅹ 10',8.71,11.0,60.0,60.0,10.0,6.5,0.0,1.86,1.86,35.5,35.5,0.79,55.9,15.1,1.79,1.79,2.25,1.17,8.57,8.57,15.4,15.4,'IS808_Rev',3.66); +INSERT INTO EqualAngle VALUES(77,'∠65 ⅹ 65ⅹ 10',9.49,12.0,65.0,65.0,10.0,6.5,0.0,1.98,1.98,45.9,45.9,0.79,72.5,19.4,1.95,1.95,2.45,1.27,10.1,10.1,18.3,18.3,'IS808_Rev',4.0); +INSERT INTO EqualAngle VALUES(78,'∠ 70 ⅹ 70ⅹ 7',7.39,9.42,70.0,70.0,7.0,7.0,0.0,2.0,2.0,43.4,43.4,0.79,68.8,17.9,2.15,2.15,2.7,1.38,8.66,8.66,15.5,15.6,'IS808_Rev',1.52); +INSERT INTO EqualAngle VALUES(79,'∠ 100 ⅹ 100ⅹ 7',10.73,13.6,100.0,100.0,7.0,8.5,0.0,2.74,2.74,132.0,132.0,0.79,210.0,54.2,3.11,3.11,3.92,1.99,18.2,18.2,32.7,32.7,'IS808_Rev',2.2); +INSERT INTO EqualAngle VALUES(80,'∠ 100 ⅹ 100ⅹ 15',21.91,27.9,100.0,100.0,15.0,8.5,0.0,3.04,3.04,252.0,252.0,0.79,398.0,106.0,3.01,3.01,3.78,1.95,36.2,36.2,65.3,65.4,'IS808_Rev',20.8); +INSERT INTO EqualAngle VALUES(81,'∠ 120 ⅹ 120ⅹ 8',14.66,18.6,120.0,120.0,8.0,10.0,4.8,3.25,3.25,258.0,258.0,0.79,410.0,105.0,3.72,3.72,4.69,2.38,29.5,29.5,53.4,53.5,'IS808_Rev',3.95); +INSERT INTO EqualAngle VALUES(82,'∠ 120 ⅹ 120ⅹ 10',18.15,23.1,120.0,120.0,10.0,10.0,4.8,3.34,3.34,315.0,315.0,0.79,501.0,129.0,3.69,3.69,4.66,2.36,36.4,36.4,65.9,66.0,'IS808_Rev',7.66); +INSERT INTO EqualAngle VALUES(83,'∠ 120 ⅹ 120ⅹ 12',21.57,27.4,120.0,120.0,12.0,10.0,4.8,3.42,3.42,370.0,370.0,0.79,588.0,152.0,3.67,3.67,4.63,2.35,43.1,43.1,78.0,78.1,'IS808_Rev',13.1); +INSERT INTO EqualAngle VALUES(84,'∠ 120 ⅹ 120ⅹ 15',26.58,33.8,120.0,120.0,15.0,10.0,4.8,3.53,3.53,447.0,447.0,0.79,709.0,185.0,3.64,3.64,4.58,2.34,52.8,52.8,95.5,95.6,'IS808_Rev',25.3); +INSERT INTO EqualAngle VALUES(85,'∠ 130 ⅹ 130ⅹ 9',17.82,22.7,130.0,130.0,9.0,10.0,4.8,3.55,3.55,368.0,368.0,0.79,586.0,150.0,4.03,4.03,5.08,2.57,39.0,39.0,70.5,70.6,'IS808_Rev',6.09); +INSERT INTO EqualAngle VALUES(86,'∠150 ⅹ 150ⅹ 15',33.72,42.9,150.0,150.0,15.0,12.0,4.8,4.28,4.28,907.0,907.0,0.79,1440.0,372.0,4.6,4.6,5.79,2.95,84.6,84.6,152.0,152.0,'IS808_Rev',32.0); +INSERT INTO EqualAngle VALUES(87,'∠150 ⅹ 150ⅹ 18',40.01,50.9,150.0,150.0,18.0,12.0,4.8,4.39,4.39,1050.0,1050.0,0.79,1680.0,437.0,4.56,4.56,5.74,2.93,99.8,99.8,180.0,180.0,'IS808_Rev',54.8); +INSERT INTO EqualAngle VALUES(88,'∠180 ⅹ 180ⅹ 15',41.09,52.3,180.0,180.0,15.0,18.0,4.8,5.0,5.0,1610.0,1610.0,0.79,2550.0,663.0,5.55,5.55,6.99,3.56,123.0,123.0,223.0,223.0,'IS808_Rev',38.8); +INSERT INTO EqualAngle VALUES(89,'∠180 ⅹ 180ⅹ 18',48.79,62.1,180.0,180.0,18.0,18.0,4.8,5.12,5.12,1880.0,1880.0,0.79,2990.0,778.0,5.51,5.51,6.94,3.54,146.0,146.0,264.0,264.0,'IS808_Rev',66.4); +INSERT INTO EqualAngle VALUES(90,'∠180 ⅹ 180ⅹ 20',53.85,68.6,180.0,180.0,20.0,18.0,4.8,5.2,5.2,2060.0,2060.0,0.79,3270.0,853.0,5.49,5.49,6.91,3.53,161.0,161.0,290.0,291.0,'IS808_Rev',90.6); +INSERT INTO EqualAngle VALUES(91,'∠200 ⅹ 200ⅹ 24',71.31,90.8,200.0,200.0,24.0,18.0,4.8,5.85,5.85,3350.0,3350.0,0.79,5320.0,1390.0,6.08,6.08,7.65,3.91,237.0,237.0,427.0,428.0,'IS808_Rev',173.0); +CREATE TABLE IF NOT EXISTS "Columns" ( + "Id" INTEGER, + "Designation" VARCHAR(50), + "Mass" REAL(10 , 2), + "Area" REAL(10 , 2), + "D" REAL(10 , 2), + "B" REAL(10 , 2), + "tw" REAL(10 , 2), + "T" INTEGER(10 , 2), + "FlangeSlope" INTEGER DEFAULT (null), + "R1" REAL(10 , 2), + "R2" REAL(10 , 2), + "Iz" REAL(10 , 2), + "Iy" REAL(10 , 2), + "rz" REAL(10 , 2), + "ry" REAL(10 , 2), + "Zz" REAL(10 , 2), + "Zy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "It" REAL(10 , 2), + "Iw" REAL(10 , 2), + "Source" VARCHAR(100), + "Type" BVARCHAR(100), + PRIMARY KEY("Id") +); +INSERT INTO Columns VALUES(1,'HB 150',27.06,34.4,150.0,150.0,5.4,9,94,8.0,4.0,1450.0,431.0,6.49,3.53,194.0,57.5,215.0,92.7,10.1,25100.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(2,'HB 150*',30.15,38.4,150.0,150.0,8.4,9,94,8.0,4.0,1510.0,435.0,6.27,3.36,201.0,58.0,228.0,94.7,12.6,25100.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(3,'HB 150*',33.66,42.9,150.0,150.0,11.8,9,94,8.0,4.0,1570.0,439.0,6.06,3.2,210.0,58.6,243.0,97.6,17.4,25100.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(4,'HB 200',37.31,47.5,200.0,200.0,6.1,9,94,9.0,4.5,3600.0,967.0,8.71,4.51,360.0,96.7,397.0,159.0,14.9,109000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(5,'HB 200*',39.73,50.6,200.0,200.0,7.8,9,94,9.0,4.5,3690.0,971.0,8.54,4.38,369.0,97.1,411.0,160.0,16.6,109000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(6,'HB 225',43.12,54.9,225.0,225.0,6.5,9.1,94,10.0,5.0,5280.0,1350.0,9.8,4.96,469.0,120.0,515.0,200.0,18.3,201000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(7,'HB 225*',46.52,59.2,225.0,225.0,8.6,9.1,94,10.0,5.0,5430.0,1360.0,9.57,4.79,483.0,121.0,538.0,203.0,20.8,201000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(8,'HB 250',50.98,64.9,250.0,250.0,6.9,9.7,94,10.0,5.0,7730.0,1960.0,10.9,5.49,619.0,156.0,678.0,262.0,24.5,364000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(9,'HB 250*',54.41,69.3,250.0,250.0,8.8,9.7,94,10.0,5.0,7930.0,1970.0,10.6,5.33,634.0,157.0,704.0,264.0,27.2,364000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(10,'HB 300',58.74,74.8,300.0,250.0,7.6,10.6,94,11.0,5.5,12500.0,2190.0,12.9,5.41,836.0,175.0,921.0,291.0,32.4,577000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(11,'HB 300*',62.67,79.8,300.0,250.0,9.4,10.6,94,11.0,5.5,12800.0,2200.0,12.6,5.25,858.0,176.0,956.0,294.0,36.2,577000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(12,'HB 350',67.42,85.9,350.0,250.0,8.3,11.6,94,12.0,6.0,19100.0,2450.0,14.9,5.34,1090.0,196.0,1210.0,324.0,42.8,864000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(13,'HB 350*',72.03,91.7,350.0,250.0,10.1,11.6,94,12.0,6.0,19600.0,2460.0,14.6,5.17,1120.0,196.0,1260.0,328.0,48.3,864000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(14,'HB 400',77.43,98.6,400.0,250.0,9.1,12.7,94,14.0,7.0,28000.0,2720.0,16.8,5.25,1400.0,218.0,1560.0,360.0,57.8,1240000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(15,'HB 400*',81.83,104.0,400.0,250.0,10.6,12.7,94,14.0,7.0,28700.0,2730.0,16.6,5.12,1430.0,218.0,1610.0,364.0,63.9,1240000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(16,'HB 450',87.22,111.0,450.0,250.0,9.8,13.7,94,15.0,7.5,39200.0,2980.0,18.7,5.18,1740.0,238.0,1950.0,394.0,73.5,1690000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(17,'HB 450*',92.19,117.0,450.0,250.0,11.3,13.7,94,15.0,7.5,40100.0,2990.0,18.4,5.04,1780.0,239.0,2020.0,398.0,81.5,1690000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(18,'PBP 200 X 43.85',43.85,55.8,200.0,205.0,9.3,9.3,90,10.0,0.0,3990.0,1330.0,8.46,4.89,399.0,130.0,447.0,199.0,17.9,121000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(19,'PBP 200 X 53.49',53.49,68.1,204.0,207.0,11.3,11.3,90,10.0,0.0,4970.0,1670.0,8.54,4.96,487.0,161.0,551.0,248.0,31.9,155000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(20,'PBP 220 X 57.28',57.28,72.9,210.0,225.0,11.0,11,90,18.0,0.0,5730.0,2090.0,8.87,5.36,546.0,186.0,614.0,286.0,37.6,206000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(21,'PBP 260 X 75.01',75.01,95.5,249.0,265.0,12.0,12,90,24.0,0.0,10600.0,3730.0,10.5,6.25,854.0,281.0,958.0,435.0,64.3,522000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(22,'PBP 260 X 87.3',87.3,111.0,253.0,267.0,14.0,14,90,24.0,0.0,12500.0,4450.0,10.6,6.33,993.0,333.0,1120.0,516.0,96.6,634000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(23,'PBP 300 X 76.92',76.92,97.9,299.0,306.0,10.8,10.8,90,15.0,0.0,16000.0,5160.0,12.7,7.26,1070.0,337.0,1180.0,515.0,43.5,1070000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(24,'PBP 300 X 88.46',88.46,112.0,302.0,308.0,12.4,12.4,90,15.0,0.0,18500.0,6040.0,12.8,7.32,1220.0,392.0,1370.0,600.0,65.0,1260000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(25,'PBP 300 X 95',95.0,121.0,304.0,309.0,13.3,13.3,90,15.0,0.0,20000.0,6540.0,12.8,7.36,1320.0,423.0,1470.0,649.0,79.8,1380000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(26,'PBP 300 X 109.54',109.54,139.0,308.0,311.0,15.3,15.3,90,15.0,0.0,23400.0,7680.0,12.9,7.42,1520.0,494.0,1710.0,758.0,120.0,1640000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(27,'PBP 300 X 124.2',124.2,158.0,312.0,313.0,17.3,17.3,90,15.0,0.0,26900.0,8850.0,13.0,7.48,1720.0,565.0,1950.0,870.0,173.0,1910000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(28,'PBP 300 X 150.01',150.01,191.0,319.0,316.0,20.8,20.8,90,15.0,0.0,33200.0,10900.0,13.2,7.57,2080.0,693.0,2380.0,1070.0,300.0,2430000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(29,'PBP 300 X 180.12',180.12,229.0,327.0,320.0,24.8,24.8,90,15.0,0.0,41000.0,13500.0,13.3,7.69,2500.0,849.0,2900.0,1310.0,510.0,3090000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(30,'PBP 300 X 184.12',184.12,234.0,328.0,321.0,25.3,25.3,90,15.0,0.0,42000.0,13900.0,13.3,7.72,2560.0,871.0,2970.0,1350.0,542.0,3190000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(31,'PBP 300 X 222.58',222.58,283.0,338.0,326.0,30.3,30.3,90,15.0,0.0,52500.0,17500.0,13.6,7.87,3100.0,1070.0,3640.0,1670.0,936.0,4140000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(32,'PBP 320 X 88.48',88.48,112.0,303.0,304.0,12.0,12,90,27.0,0.0,18700.0,5630.0,12.8,7.07,1230.0,370.0,1370.0,572.0,78.8,1180000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(33,'PBP 320 X 102.84',102.84,131.0,307.0,306.0,14.0,14,90,27.0,0.0,22000.0,6700.0,12.9,7.15,1430.0,438.0,1610.0,677.0,117.0,1430000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(34,'PBP 320 X 117.33',117.33,149.0,311.0,308.0,16.0,16,90,27.0,0.0,25400.0,7810.0,13.0,7.23,1630.0,507.0,1840.0,785.0,167.0,1690000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(35,'PBP 320 X 146.69',146.69,186.0,319.0,312.0,20.0,20,90,27.0,0.0,32600.0,10100.0,13.2,7.37,2040.0,651.0,2330.0,1010.0,309.0,2260000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(36,'PBP 320 X 184.1',184.1,234.0,329.0,317.0,25.0,25,90,27.0,0.0,42200.0,13300.0,13.4,7.54,2560.0,841.0,2970.0,1310.0,586.0,3060000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(37,'PBP 360 X 152.2',152.2,193.0,356.0,376.0,18.0,17.9,90,15.0,0.0,43800.0,15800.0,15.0,9.0,2460.0,844.0,2760.0,1290.0,225.0,4530000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(38,'PBP 360 X 174.2',174.2,221.0,361.0,379.0,20.0,20.4,90,15.0,0.0,50900.0,18500.0,15.1,9.1,2820.0,978.0,3180.0,1500.0,325.0,5360000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(39,'PBP 360 X 178.4',178.4,227.0,362.0,379.0,21.0,20.9,90,15.0,0.0,52200.0,18900.0,15.2,9.1,2880.0,1000.0,3260.0,1530.0,357.0,5510000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(40,'PBP 400 X 122.4',122.4,155.0,348.0,390.0,14.0,14,90,15.0,0.0,34700.0,13800.0,14.9,9.4,1990.0,710.0,2210.0,1080.0,111.0,3860000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(41,'PBP 400 X 140.2',140.2,178.0,352.0,392.0,16.0,16,90,15.0,0.0,40200.0,16000.0,15.0,9.5,2280.0,820.0,2540.0,1250.0,165.0,4530000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(42,'PBP 400 X 158.1',158.1,201.0,356.0,394.0,18.0,18,90,15.0,0.0,45900.0,18300.0,15.1,9.6,2570.0,932.0,2880.0,1420.0,234.0,5240000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(43,'PBP 400 X 176.1',176.1,224.0,360.0,396.0,20.0,20,90,15.0,0.0,51700.0,20700.0,15.2,9.6,2870.0,1040.0,3230.0,1600.0,321.0,5980000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(44,'PBP 400 X 194.3',194.3,247.0,364.0,398.0,22.0,22,90,15.0,0.0,57600.0,23100.0,15.3,9.7,3160.0,1160.0,3580.0,1780.0,428.0,6750000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(45,'PBP 400 X 212.5',212.5,270.0,368.0,400.0,24.0,24,90,15.0,0.0,63800.0,25600.0,15.4,9.7,3460.0,1280.0,3940.0,1960.0,556.0,7570000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(46,'PBP 400 X 230.9',230.9,294.0,372.0,402.0,26.0,26,90,15.0,0.0,70100.0,28200.0,15.4,9.8,3770.0,1400.0,4310.0,2150.0,707.0,8420000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(47,'SC 100',19.97,25.4,100.0,100.0,6.0,10,98,12.0,6.0,434.0,136.0,4.13,2.31,87.0,27.2,101.0,45.2,10.6,3370.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(48,'SC 120',26.22,33.4,120.0,120.0,6.5,11,98,12.0,6.0,840.0,255.0,5.02,2.77,140.0,42.6,161.0,70.8,16.5,9400.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(49,'SC 140',33.25,42.3,140.0,140.0,7.0,12,98,12.0,6.0,1470.0,437.0,5.9,3.21,210.0,62.5,240.0,104.0,24.6,22400.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(50,'SC 150*',36.93,47.0,152.0,152.0,7.9,11.9,98,11.7,3.0,1920.0,554.0,6.39,3.43,253.0,72.9,288.0,122.0,27.6,34100.0,'IS808_Old',NULL); +INSERT INTO Columns VALUES(51,'SC 160',41.85,53.3,160.0,160.0,8.0,13,98,15.0,7.5,2410.0,694.0,6.74,3.61,302.0,86.8,345.0,146.0,38.3,47900.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(52,'SC 180',50.48,64.3,180.0,180.0,8.5,14,98,15.0,7.5,3730.0,1050.0,7.62,4.05,414.0,117.0,471.0,197.0,52.8,93700.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(53,'SC 200',60.24,76.7,200.0,200.0,9.0,15,98,18.0,9.0,5520.0,1520.0,8.49,4.46,552.0,152.0,627.0,259.0,74.9,171000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(54,'SC 220',70.41,89.6,220.0,220.0,9.5,16,98,18.0,9.0,7860.0,2150.0,9.37,4.9,715.0,196.0,809.0,333.0,98.4,295000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(55,'SC 250',85.54,108.0,250.0,250.0,10.0,17,98,23.0,11.5,12400.0,3250.0,10.6,5.47,995.0,260.0,1120.0,448.0,143.0,600000.0,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(56,'UC 152 x 152 x 23',23.0,29.2,152.4,152.2,5.8,6.8,90,7.6,0.0,1250.0,400.0,6.54,3.7,164.0,52.5,182.0,80.2,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(57,'UC 152 x 152 x 30',30.0,38.3,157.6,152.9,6.5,9.4,90,7.6,0.0,1748.0,560.0,6.76,3.83,222.0,73.3,248.0,112.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(58,'UC 152 x 152 x 37',37.0,47.1,161.8,154.4,8.0,11.5,90,7.6,0.0,2210.0,706.0,6.85,3.87,273.0,91.5,309.0,140.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(59,'UC 203 x 203 x 46',46.1,58.7,203.2,203.6,7.2,11,90,10.2,0.0,4568.0,1548.0,8.82,5.13,450.0,152.0,497.0,231.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(60,'UC 203 x 203 x 52',52.0,66.3,206.2,204.3,7.9,12.5,90,10.2,0.0,5259.0,1777.0,8.91,5.18,510.0,174.0,567.0,264.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(61,'UC 203 x 203 x 60',60.0,76.4,209.6,205.8,9.4,14.2,90,10.2,0.0,6125.0,2064.0,8.95,5.2,584.0,201.0,656.0,305.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(62,'UC 203 x 203 x 71',71.0,90.4,215.8,206.4,10.0,17.3,90,10.2,0.0,7618.0,2537.0,9.18,5.3,706.0,246.0,799.0,374.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(63,'UC 203 x 203 x 86',86.1,109.6,222.2,209.1,12.7,20.5,90,10.2,0.0,9449.0,3127.0,9.28,5.34,850.0,299.0,977.0,456.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(64,'UC 254 x 254 x 107',107.1,136.4,266.7,258.8,12.8,20.5,90,12.7,0.0,17510.0,5927.0,11.3,6.59,1313.0,458.0,1484.0,697.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(65,'UC 254 x 254 x 132',132.0,168.1,276.3,261.3,15.3,25.3,90,12.7,0.0,22529.0,7531.0,11.6,6.69,1631.0,576.0,1869.0,878.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(66,'UC 254 x 254 x 167',167.1,212.9,289.1,265.2,19.2,31.7,90,12.7,0.0,29998.0,9869.0,11.9,6.81,2075.0,744.0,2424.0,1137.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(67,'UC 254 x 254 x 73',73.1,93.1,254.1,254.6,8.6,14.2,90,12.7,0.0,11407.0,3907.0,11.1,6.48,898.0,307.0,992.0,465.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(68,'UC 254 x 254 x 89',88.9,113.3,260.3,256.3,10.3,17.3,90,12.7,0.0,14268.0,4857.0,11.2,6.55,1096.0,379.0,1224.0,575.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(69,'UC 305 x 305 x 118',117.9,150.2,314.5,307.4,12.0,18.7,90,15.2,0.0,27672.0,9058.0,13.6,7.77,1760.0,589.0,1958.0,895.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(70,'UC 305 x 305 x 137',136.9,174.4,320.5,309.2,13.8,21.7,90,15.2,0.0,32814.0,10698.0,13.7,7.83,2048.0,692.0,2297.0,1053.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(71,'UC 305 x 305 x 158',158.1,201.4,327.1,311.2,15.8,25,90,15.2,0.0,38747.0,12568.0,13.9,7.9,2369.0,808.0,2680.0,1230.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(72,'UC 305 x 305 x 198',198.1,252.4,339.9,314.5,19.1,31.4,90,15.2,0.0,50904.0,16298.0,14.2,8.04,2995.0,1036.0,3440.0,1581.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(73,'UC 305 x 305 x 240',240.0,305.8,352.5,318.4,23.0,37.7,90,15.2,0.0,64203.0,20313.0,14.5,8.15,3643.0,1276.0,4247.0,1951.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(74,'UC 305 x 305 x 283',282.9,360.4,365.3,322.2,26.8,44.1,90,15.2,0.0,78872.0,24633.0,14.8,8.27,4318.0,1529.0,5105.0,2342.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(75,'UC 305 x 305 x 97',96.9,123.4,307.9,305.3,9.9,15.4,90,15.2,0.0,22249.0,7307.0,13.4,7.69,1445.0,479.0,1592.0,726.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(76,'UC 356 x 368 x 129',129.0,164.3,355.6,368.6,10.4,17.5,90,15.2,0.0,40246.0,14610.0,15.6,9.43,2264.0,793.0,2479.0,1199.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(77,'UC 356 x 368 x 153',152.9,194.8,362.0,370.5,12.3,20.7,90,15.2,0.0,48589.0,17552.0,15.8,9.49,2684.0,947.0,2965.0,1435.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(78,'UC 356 x 368 x 177',177.0,225.5,368.2,372.6,14.4,23.8,90,15.2,0.0,57118.0,20528.0,15.9,9.54,3103.0,1102.0,3455.0,1671.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(79,'UC 356 x 368 x 202',201.9,257.2,374.6,374.7,16.5,27,90,15.2,0.0,66261.0,23687.0,16.1,9.6,3538.0,1264.0,3972.0,1920.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(80,'UC 356 x 406 x 235',235.1,299.4,381.0,394.8,18.4,30.2,90,15.2,0.0,79085.0,30992.0,16.3,10.2,4151.0,1570.0,4687.0,2383.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(81,'UC 356 x 406 x 287',287.1,365.7,393.6,399.0,22.6,36.5,90,15.2,0.0,99875.0,38676.0,16.5,10.3,5075.0,1939.0,5812.0,2949.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(82,'UC 356 x 406 x 340',339.9,433.0,406.4,403.0,26.6,42.9,90,15.2,0.0,122543.0,46851.0,16.8,10.4,6031.0,2325.0,6999.0,3544.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(83,'UC 356 x 406 x 393',393.0,500.6,419.0,407.0,30.6,49.2,90,15.2,0.0,146618.0,55365.0,17.1,10.5,6998.0,2721.0,8222.0,4154.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(84,'UC 356 x 406 x 467',467.0,594.9,436.6,412.2,35.8,58,90,15.2,0.0,183003.0,67831.0,17.5,10.7,8383.0,3291.0,10002.0,5034.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(85,'UC 356 x 406 x 551',551.0,701.9,455.6,418.5,42.1,67.5,90,15.2,0.0,226938.0,82668.0,18.0,10.9,9962.0,3951.0,12076.0,6058.0,NULL,NULL,'IS808_Rev',NULL); +INSERT INTO Columns VALUES(86,'UC 356 x 406 x 634',633.9,807.5,474.6,424.0,47.6,77,90,15.2,0.0,274845.0,98122.0,18.4,11.0,11582.0,4628.0,14235.0,7108.0,NULL,NULL,'IS808_Rev',NULL); +CREATE TABLE IF NOT EXISTS "Beams" ( + "Id" INTEGER, + "Designation" VARCHAR(50), + "Mass" REAL(10 , 2), + "Area" REAL(10 , 2), + "D" REAL(10 , 2), + "B" REAL(10 , 2), + "tw" REAL(10 , 2), + "T" REAL(10 , 2), + "FlangeSlope" INTEGER, + "R1" REAL(10 , 2), + "R2" REAL(10 , 2), + "Iz" REAL(10 , 2), + "Iy" REAL(10 , 2), + "rz" REAL(10 , 2), + "ry" REAL(10 , 2), + "Zz" REAL(10 , 2), + "Zy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "It" REAL(10 , 2), + "Iw" REAL(10 , 2), + "Source" VARCHAR(100), + "Type" VARCHAR(100), + PRIMARY KEY("Id") +); +INSERT INTO Beams VALUES(1,'JB 150',7.07,9.0,150.0,50.0,3.0,4.6,91.5,5.0,1.5,321.0,9.21,5.97,1.01,42.8,3.68,49.5,5.96,0.54800000000000004263,506.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(2,'JB 175',8.07,10.2,175.0,50.0,3.2,4.8,91.5,5.0,1.5,480.0,9.65,6.83,0.96899999999999995026,54.9,3.86,64.2,6.32,0.65600000000000004973,724.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(3,'JB 200',9.92,12.6,200.0,60.0,3.4,5.0,91.5,5.0,1.5,780.0,17.2,7.85,1.16,78.0,5.76,90.9,9.35,0.87300000000000004263,1710.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(4,'JB 225',12.78,16.2,225.0,80.0,3.7,5.0,91.5,6.5,1.5,1310.0,40.4,8.97,1.57,116.0,10.1,134.0,16.2,1.27,5160.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(5,'LB 75',6.05,7.71,75.0,50.0,3.7,5.0,91.5,6.5,2.0,72.7,10.0,3.07,1.13,19.3,4.0,22.3,6.39,0.73700000000000001065,127.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(6,'LB 100',8.01,10.2,100.0,50.0,4.0,6.4,91.5,7.0,3.0,168.0,12.7,4.05,1.11,33.6,5.08,38.9,8.2,1.38,292.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(7,'LB(P) 100',8.75,11.1,100.0,50.0,4.3,7.0,91.5,8.0,3.0,181.0,14.0,4.04,1.12,36.3,5.6,42.3,9.06,1.86,315.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(8,'LB 125',11.87,15.1,125.0,75.0,4.4,6.5,91.5,8.0,3.0,406.0,43.3,5.18,1.69,65.1,11.5,73.9,18.3,2.21,1600.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(9,'LB 150',14.19,18.0,150.0,80.0,4.8,6.8,91.5,9.5,3.0,687.0,55.2,6.16,1.74,91.7,13.8,104.0,22.1,3.02,2970.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(10,'LB 175',16.59,21.1,175.0,90.0,5.0,6.9,91.5,9.5,3.0,1090.0,79.5,7.18,1.94,124.0,17.6,141.0,28.2,3.55,5920.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(11,'LB(P) 175',16.6,21.1,175.0,80.0,5.2,7.7,96,9.5,3.0,1060.0,57.2,7.1,1.64,122.0,14.3,140.0,23.9,4.5,4590.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(12,'LB 200',19.83,25.2,200.0,100.0,5.4,7.3,91.5,9.5,3.0,1690.0,115.0,8.19,2.13,169.0,23.0,192.0,36.9,4.61,11200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(13,'LB(P) 200',21.06,26.8,200.0,100.0,5.6,8.0,96,9.5,3.0,1800.0,112.0,8.19,2.05,180.0,22.5,205.0,37.7,6.27,12200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(14,'LB 225',23.47,29.9,225.0,100.0,5.8,8.6,98,12.0,6.0,2500.0,112.0,9.14,1.94,222.0,22.5,254.0,39.2,8.47,16700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(15,'LB 250',27.87,35.5,250.0,125.0,6.1,8.2,98,13.0,6.5,3720.0,193.0,10.2,2.33,297.0,30.9,338.0,55.3,10.2,39000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(16,'LB 275',32.96,42.0,275.0,140.0,6.4,8.8,98,14.0,7.0,5370.0,287.0,11.3,2.61,391.0,41.0,443.0,73.5,14.0,71200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(17,'LB 300',37.72,48.0,300.0,150.0,6.7,9.4,98,15.0,7.5,7340.0,376.0,12.3,2.79,489.0,50.1,554.0,89.9,18.1,111000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(18,'LB(P) 300',41.5,52.8,300.0,140.0,7.0,11.6,98,15.0,7.5,8140.0,414.0,12.4,2.79,542.0,59.2,614.0,101.0,26.3,110000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(19,'LB 325',43.07,54.8,325.0,165.0,7.0,9.8,98,16.0,8.0,9880.0,510.0,13.4,3.05,608.0,61.9,688.0,111.0,22.8,182000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(20,'LB 350',49.44,63.0,350.0,165.0,7.4,11.4,98,16.0,8.0,13100.0,632.0,14.4,3.16,752.0,76.6,851.0,134.0,32.3,244000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(21,'LB 400',56.82,72.4,400.0,165.0,8.0,12.5,98,16.0,8.0,19300.0,716.0,16.3,3.14,965.0,86.8,1090.0,151.0,41.2,351000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(22,'LB 450',65.22,83.1,450.0,170.0,8.6,13.4,98,16.0,8.0,27500.0,853.0,18.2,3.2,1220.0,100.0,1400.0,174.0,51.8,522000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(23,'LB 500',74.92,95.4,500.0,180.0,9.2,14.1,98,17.0,8.5,38500.0,1060.0,20.1,3.33,1540.0,118.0,1770.0,206.0,65.5,808000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(24,'LB 550',86.28,109.0,550.0,190.0,9.9,15.0,98,18.0,9.0,53100.0,1330.0,21.9,3.48,1930.0,140.0,2220.0,246.0,84.5,1220000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(25,'LB 600',99.39,126.0,600.0,210.0,10.5,15.5,98,20.0,10.0,72900.0,1820.0,23.9,3.79,2430.0,173.0,2790.0,306.0,107.0,2040000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(26,'MB 100',8.95,11.4,100.0,50.0,4.7,7.0,98,9.0,4.5,182.0,12.5,3.99,1.04,36.4,5.01,42.6,8.58,2.15,315.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(27,'MB 125',13.35,17.0,125.0,70.0,5.0,8.0,98,9.0,4.5,445.0,38.4,5.11,1.5,71.3,10.9,82.1,18.4,3.99,1560.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(28,'MB 150',14.96,19.0,150.0,75.0,5.0,8.0,98,9.0,4.5,718.0,46.7,6.13,1.56,95.7,12.4,109.0,21.0,4.36,2830.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(29,'MB 175',19.5,24.8,175.0,85.0,5.8,9.0,98,10.0,5.0,1260.0,76.6,7.12,1.75,144.0,18.0,165.0,30.5,7.17,6340.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(30,'MB 200',24.17,30.8,200.0,100.0,5.7,10.0,98,11.0,5.5,2110.0,136.0,8.28,2.1,211.0,27.3,240.0,46.0,10.7,15000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(31,'MB 225',31.15,39.7,225.0,110.0,6.5,11.8,98,12.0,6.0,3440.0,218.0,9.31,2.34,306.0,39.6,348.0,66.3,18.6,29700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(32,'MB 250',37.3,47.5,250.0,125.0,6.9,12.5,98,13.0,6.5,5130.0,334.0,10.3,2.65,410.0,53.5,465.0,89.7,25.5,57300.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(33,'MB 300',46.02,58.6,300.0,140.0,7.7,13.1,98,14.0,7.0,8990.0,486.0,12.3,2.87,599.0,69.4,681.0,117.0,34.7,123000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(34,'MB 350',52.33,66.7,350.0,140.0,8.1,14.2,98,14.0,7.0,13600.0,537.0,14.2,2.83,779.0,76.8,889.0,129.0,43.1,183000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(35,'MB 400',61.55,78.4,400.0,140.0,8.9,16.0,98,14.0,7.0,20400.0,622.0,16.1,2.81,1020.0,88.8,1170.0,149.0,59.6,269000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(36,'MB 450',72.38,92.2,450.0,150.0,9.4,17.4,98,15.0,7.5,30400.0,834.0,18.1,3.0,1350.0,111.0,1550.0,187.0,81.0,457000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(37,'MB 500',86.88,110.0,500.0,180.0,10.2,17.2,98,17.0,8.5,45200.0,1360.0,20.2,3.51,1800.0,152.0,2070.0,259.0,103.0,974000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(38,'MB 550',103.64,132.0,550.0,190.0,11.2,19.3,98,18.0,9.0,64900.0,1830.0,22.1,3.72,2360.0,193.0,2710.0,328.0,150.0,1550000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(39,'MB 600',121.0,154.0,600.0,210.0,12.0,20.3,98,20.0,10.0,90200.0,2570.0,24.1,4.08,3000.0,245.0,3450.0,418.0,198.0,2630000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(40,'NPB 100 X 55 X 8.1',8.1,10.3,100.0,55.0,4.1,5.7,90,7.0,0.0,171.0,15.9,4.07,1.24,34.2,5.78,39.4,9.14,1.15,351.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(41,'NPB 120 X 60 X 10.37',10.37,13.2,120.0,64.0,4.4,6.3,90,7.0,0.0,317.0,27.6,4.9,1.44,52.9,8.64,60.7,13.5,1.69,889.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(42,'NPB 140 X 70 X 12.89',12.89,16.4,140.0,73.0,4.7,6.9,90,7.0,0.0,541.0,44.9,5.74,1.65,77.3,12.3,88.3,19.2,2.4,1980.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(43,'NPB 160 X 80 X 15.77',15.77,20.0,160.0,82.0,5.0,7.4,90,9.0,0.0,869.0,68.3,6.57,1.84,108.0,16.6,123.0,26.1,3.54,3950.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(44,'NPB 180 X 90 X 15.37',15.37,19.5,177.0,91.0,4.3,6.5,90,9.0,0.0,1060.0,81.8,7.36,2.04,120.0,17.9,135.0,27.9,2.67,5930.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(45,'NPB 180 X 90 X 18.8',18.8,23.9,180.0,91.0,5.3,8.0,90,9.0,0.0,1310.0,100.0,7.41,2.05,146.0,22.1,166.0,34.6,4.72,7430.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(46,'NPB 180 X 90 X 21.27',21.27,27.0,182.0,92.0,6.0,9.0,90,9.0,0.0,1500.0,117.0,7.45,2.08,165.0,25.4,189.0,39.9,6.64,8730.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(47,'NPB 200 X 100 X 18.43',18.43,23.4,197.0,100.0,4.5,7.0,90,12.0,0.0,1590.0,117.0,8.23,2.23,161.0,23.4,181.0,36.5,4.13,10500.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(48,'NPB 200 X 100 X 22.36',22.36,28.4,200.0,100.0,5.6,8.5,90,12.0,0.0,1940.0,142.0,8.26,2.23,194.0,28.4,220.0,44.6,6.92,12900.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(49,'NPB 200 X 100 X 25.09',25.09,31.9,202.0,102.0,6.2,9.5,90,12.0,0.0,2210.0,168.0,8.31,2.29,218.0,33.1,249.0,51.8,9.36,15500.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(50,'NPB 200 X 130 X 27.37',27.37,34.8,207.0,133.0,5.8,8.5,90,12.0,0.0,2660.0,334.0,8.74,3.09,257.0,50.2,288.0,77.4,8.48,32800.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(51,'NPB 200 X 130 X 31.56',31.56,40.1,210.0,134.0,6.4,10.0,90,12.0,0.0,3150.0,401.0,8.85,3.16,300.0,59.9,337.0,92.4,12.8,40100.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(52,'NPB 200 X 150 X 30.46',30.46,38.7,194.0,150.0,6.0,9.0,90,12.0,0.0,2670.0,507.0,8.3,3.61,275.0,67.6,306.0,103.0,10.4,43300.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(53,'NPB 200 X 165 X 35.69',35.69,45.4,201.0,165.0,6.2,10.0,90,12.0,0.0,3410.0,749.0,8.66,4.06,339.0,90.8,376.0,138.0,14.5,68200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(54,'NPB 200 X 165 X 42.48',42.48,54.1,205.0,166.0,7.2,12.0,90,12.0,0.0,4160.0,915.0,8.77,4.11,406.0,110.0,454.0,168.0,24.1,85100.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(55,'NPB 200 X 165 X 48.0',48.0,61.1,210.0,166.0,6.5,14.5,90,12.0,0.0,5020.0,1100.0,9.06,4.25,478.0,133.0,534.0,202.0,37.9,105000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(56,'NPB 220 X 110 X 22.18',22.18,28.2,217.0,110.0,5.0,7.7,90,12.0,0.0,2310.0,171.0,9.05,2.46,213.0,31.1,240.0,48.4,5.68,18700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(57,'NPB 220 X 110 X 26.2',26.2,33.3,220.0,110.0,5.9,9.2,90,12.0,0.0,2770.0,204.0,9.11,2.47,251.0,37.2,285.0,58.1,9.03,22600.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(58,'NPB 220 X 110 X 29.35',29.35,37.3,222.0,112.0,6.6,10.2,90,12.0,0.0,3130.0,239.0,9.15,2.53,282.0,42.8,321.0,66.9,12.1,26700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(59,'NPB 240 X 120 X 26.15',26.15,33.3,237.0,120.0,5.2,8.3,90,15.0,0.0,3290.0,240.0,9.93,2.68,277.0,40.0,311.0,62.3,8.51,31200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(60,'NPB 240 X 120 X 30.71',30.71,39.1,240.0,120.0,6.2,9.8,90,15.0,0.0,3890.0,283.0,9.97,2.69,324.0,47.2,366.0,73.9,12.9,37300.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(61,'NPB 240 X 120 X 34.32',34.32,43.7,242.0,122.0,7.0,10.8,90,15.0,0.0,4360.0,328.0,9.99,2.74,361.0,53.8,410.0,84.3,17.1,43600.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(62,'NPB 250 X 125 X 30.11',30.11,38.3,250.0,125.0,6.0,9.0,90,15.0,0.0,4130.0,294.0,10.3,2.77,331.0,47.0,373.0,73.6,11.1,42500.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(63,'NPB 250 X 150 X 34.08',34.08,43.4,258.0,146.0,6.1,9.2,90,15.0,0.0,5120.0,478.0,10.8,3.32,396.0,65.5,444.0,101.0,12.8,73800.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(64,'NPB 250 X 150 X 39.78',39.78,50.6,262.0,147.0,6.6,11.2,90,15.0,0.0,6200.0,594.0,11.0,3.42,473.0,80.8,530.0,124.0,20.3,93200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(65,'NPB 250 X 150 X 46.48',46.48,59.2,266.0,148.0,7.6,13.2,90,15.0,0.0,7380.0,715.0,11.1,3.47,554.0,96.6,625.0,149.0,31.5,113000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(66,'NPB 250 X 175 X 43.94',43.94,55.9,244.0,175.0,7.0,11.0,90,15.0,0.0,6090.0,984.0,10.4,4.19,499.0,112.0,555.0,172.0,22.4,133000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(67,'NPB 270 X 135 X 30.73',30.73,39.1,267.0,135.0,5.5,8.7,90,15.0,0.0,4910.0,357.0,11.2,3.02,368.0,53.0,412.0,82.3,10.4,59500.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(68,'NPB 270 X 135 X 36.07',36.07,45.9,270.0,135.0,6.6,10.2,90,15.0,0.0,5780.0,419.0,11.2,3.02,428.0,62.2,483.0,96.9,15.9,70500.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(69,'NPB 270 X 135 X 42.26',42.26,53.8,274.0,136.0,7.5,12.2,90,15.0,0.0,6940.0,513.0,11.3,3.08,507.0,75.5,574.0,117.0,25.0,87600.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(70,'NPB 300 X 150 X 36.53',36.53,46.5,297.0,150.0,6.1,9.2,90,15.0,0.0,7170.0,518.0,12.4,3.34,483.0,69.1,541.0,107.0,13.3,107000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(71,'NPB 300 X 150 X 42.24',42.24,53.8,300.0,150.0,7.1,10.7,90,15.0,0.0,8350.0,603.0,12.4,3.35,557.0,80.5,628.0,125.0,19.9,125000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(72,'NPB 300 X 150 X 49.32',49.32,62.8,304.0,152.0,8.0,12.7,90,15.0,0.0,9990.0,745.0,12.6,3.44,657.0,98.1,743.0,152.0,30.9,157000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(73,'NPB 300 X 165 X 39.88',39.88,50.7,310.0,165.0,5.8,9.7,90,15.0,0.0,8790.0,727.0,13.1,3.78,567.0,88.1,630.0,135.0,15.4,163000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(74,'NPB 300 X 165 X 45.76',45.76,58.2,313.0,166.0,6.6,11.2,90,15.0,0.0,10200.0,855.0,13.2,3.83,652.0,103.0,727.0,158.0,22.5,194000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(75,'NPB 300 X 165 X 53.46',53.46,68.1,317.0,167.0,7.6,13.2,90,15.0,0.0,12100.0,1020.0,13.3,3.88,764.0,122.0,857.0,189.0,35.2,236000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(76,'NPB 300 X 200 X 59.57',59.57,75.8,303.0,203.0,7.5,13.1,90,15.0,0.0,12800.0,1820.0,13.0,4.9,848.0,180.0,940.0,275.0,39.5,383000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(77,'NPB 300 X 200 X 66.75',66.75,85.0,306.0,204.0,8.5,14.6,90,15.0,0.0,14500.0,2060.0,13.0,4.93,948.0,202.0,1050.0,310.0,54.3,438000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(78,'NPB 300 X 200 X 75.37',75.37,96.0,310.0,205.0,9.4,16.6,90,15.0,0.0,16600.0,2380.0,13.1,4.98,1070.0,232.0,1200.0,356.0,77.6,512000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(79,'NPB 330 X 160 X 42.97',42.97,54.7,327.0,160.0,6.5,10.0,90,18.0,0.0,10200.0,685.0,13.6,3.53,625.0,85.6,701.0,133.0,19.6,171000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(80,'NPB 330 X 160 X 49.15',49.15,62.6,330.0,160.0,7.5,11.5,90,18.0,0.0,11700.0,788.0,13.7,3.54,713.0,98.5,804.0,153.0,28.0,199000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(81,'NPB 330 X 160 X 57.01',57.01,72.6,334.0,162.0,8.5,13.5,90,18.0,0.0,13900.0,960.0,13.8,3.63,832.0,118.0,942.0,184.0,42.2,245000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(82,'NPB 350 X 170 X 50.22',50.22,63.9,357.6,170.0,6.6,11.5,90,18.0,0.0,14500.0,944.0,15.0,3.84,811.0,111.0,906.0,171.0,27.3,281000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(83,'NPB 350 X 170 X 57.1',57.1,72.7,360.0,170.0,8.0,12.7,90,18.0,0.0,16200.0,1040.0,14.9,3.78,903.0,122.0,1010.0,191.0,37.4,313000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(84,'NPB 350 X 170 X 66.05',66.05,84.1,364.0,172.0,9.2,14.7,90,18.0,0.0,19000.0,1250.0,15.0,3.85,1040.0,145.0,1180.0,226.0,55.7,380000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(85,'NPB 350 X 250 X 79.18',79.18,100.0,340.0,250.0,9.0,14.0,90,18.0,0.0,21500.0,3650.0,14.6,6.01,1260.0,292.0,1400.0,446.0,63.4,968000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(86,'NPB 400 X 180 X 57.38',57.38,73.0,397.0,180.0,7.0,12.0,90,21.0,0.0,20200.0,1170.0,16.6,4.0,1020.0,130.0,1140.0,202.0,36.1,432000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(87,'NPB 400 X 180 X 66.31',66.31,84.4,400.0,180.0,8.6,13.5,90,21.0,0.0,23100.0,1310.0,16.5,3.95,1150.0,146.0,1300.0,229.0,51.3,490000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(88,'NPB 400 X 180 X 75.67',75.67,96.3,404.0,182.0,9.7,15.5,90,21.0,0.0,26700.0,1560.0,16.6,4.02,1320.0,171.0,1500.0,269.0,73.3,587000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(89,'NPB 400 X 200 X 67.28',67.28,85.7,400.0,200.0,8.0,13.0,90,21.0,0.0,24200.0,1730.0,16.8,4.5,1210.0,173.0,1350.0,269.0,48.5,648000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(90,'NPB 450 X190 X 67.16',67.16,85.5,447.0,190.0,7.6,13.1,90,21.0,0.0,29700.0,1500.0,18.6,4.19,1330.0,158.0,1490.0,245.0,47.1,704000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(91,'NPB 450 X 190 X 77.58',77.58,98.8,450.0,190.0,9.4,14.6,90,21.0,0.0,33700.0,1670.0,18.4,4.11,1490.0,176.0,1700.0,276.0,66.7,791000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(92,'NPB 450 X 190 X 92.37',92.37,117.0,456.0,192.0,11.0,17.6,90,21.0,0.0,40900.0,2080.0,18.6,4.21,1790.0,217.0,2040.0,340.0,109.0,997000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(93,'NPB 500 X 200 X 79.36',79.36,101.0,497.0,200.0,8.4,14.5,90,21.0,0.0,42900.0,1930.0,20.6,4.38,1720.0,193.0,1940.0,301.0,64.3,1120000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(94,'NPB 500 X 200 X 90.69',90.69,115.0,500.0,200.0,10.2,16.0,90,21.0,0.0,48100.0,2140.0,20.4,4.3,1920.0,214.0,2190.0,335.0,89.1,1240000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(95,'NPB 500 X 200 X 107.32',107.32,136.0,506.0,202.0,12.0,19.0,90,21.0,0.0,57700.0,2620.0,20.5,4.37,2280.0,259.0,2610.0,408.0,142.0,1540000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(96,'NPB 550 X 210 X 92.08',92.08,117.0,547.0,210.0,9.0,15.7,90,24.0,0.0,59900.0,2430.0,22.6,4.55,2190.0,231.0,2470.0,361.0,89.3,1710000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(97,'NPB 550 X 210 X 105.52',105.52,134.0,550.0,210.0,11.1,17.2,90,24.0,0.0,67100.0,2660.0,22.3,4.45,2440.0,254.0,2780.0,400.0,122.0,1880000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(98,'NPB 550 X 210 X 122.52',122.52,156.0,556.0,212.0,12.7,20.2,90,24.0,0.0,79100.0,3220.0,22.5,4.54,2840.0,304.0,3260.0,480.0,187.0,2299999.9999999993782,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(99,'NPB 600 X 220 X 107.57',107.57,137.0,597.0,220.0,9.8,17.5,90,24.0,0.0,82900.0,3110.0,24.6,4.76,2770.0,283.0,3140.0,442.0,122.0,2600000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(100,'NPB 600 X 220 X 122.45',122.45,155.0,600.0,220.0,12.0,19.0,90,24.0,0.0,92000.0,3380.0,24.2,4.66,3060.0,307.0,3510.0,485.0,165.0,2840000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(101,'NPB 600 X 220 X 154.47',154.47,196.0,610.0,224.0,15.0,24.0,90,24.0,0.0,118000.0,4520.0,24.5,4.79,3870.0,403.0,4470.0,640.0,316.0,3850000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(102,'NPB 700 X 250 X 113.46',113.46,144.0,694.0,250.0,9.0,16.0,90,24.0,0.0,118000.0,4170.0,28.6,5.37,3420.0,334.0,3850.0,518.0,107.0,4780000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(103,'NPB 700 X 250 X 128.41',128.41,163.0,695.0,250.0,11.5,16.5,90,24.0,0.0,128000.0,4310.0,27.9,5.13,3680.0,344.0,4210.0,543.0,136.0,4940000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(104,'NPB 700 X 250 X 143.42',143.42,182.0,700.0,250.0,12.5,19.0,90,24.0,0.0,145000.0,4960.0,28.2,5.21,4160.0,397.0,4760.0,625.0,190.0,5730000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(105,'NPB 700 X 250 X 153.87',153.87,196.0,704.0,250.0,13.0,21.0,90,24.0,0.0,159000.0,5480.0,28.4,5.29,4520.0,439.0,5170.0,690.0,240.0,6370000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(106,'NPB 700 X 250 X 171.48',171.48,218.0,709.0,250.0,14.5,23.5,90,24.0,0.0,178000.0,6140.0,28.5,5.3,5030.0,491.0,5770.0,775.0,328.0,7180000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(107,'NPB 750 X 270 X 145.29',145.29,185.0,750.0,265.0,13.2,16.6,90,17.0,0.0,161000.0,5160.0,29.5,5.28,4310.0,389.0,5000.0,616.0,150.0,6920000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(108,'NPB 750 X 270 X 174.54',174.54,222.0,760.0,270.0,14.4,21.6,90,17.0,0.0,206000.0,7100.0,30.4,5.65,5430.0,526.0,6240.0,827.0,272.0,9650000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(109,'NPB 750 X 270 X 202.49',202.49,257.0,770.0,270.0,15.6,26.6,90,17.0,0.0,249000.0,8750.0,31.1,5.82,6480.0,648.0,7430.0,1010.0,450.0,11999999.999999999644,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(110,'WB 150',17.0,21.6,150.0,100.0,5.4,7.0,96,8.0,4.0,839.0,94.7,6.22,2.09,111.0,18.9,126.0,31.9,4.22,5960.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(111,'WB 175',22.06,28.1,175.0,125.0,5.8,7.4,96,8.0,4.0,1510.0,188.0,7.32,2.59,172.0,30.1,194.0,51.2,6.22,16900.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(112,'WB 200',28.8,36.7,200.0,140.0,6.1,9.0,96,9.0,4.5,2620.0,328.0,8.45,2.99,262.0,46.9,294.0,78.7,11.3,37500.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(113,'WB 200',52.09,66.4,203.0,152.0,8.9,16.5,98,15.5,7.6,4780.0,809.0,8.48,3.49,470.0,106.0,539.0,175.0,65.8,83900.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(114,'WB 225',33.93,43.2,225.0,150.0,6.4,9.9,96,9.0,4.5,3920.0,448.0,9.52,3.22,348.0,59.8,389.0,99.7,15.5,64400.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(115,'WB 250',40.84,52.0,250.0,200.0,6.7,9.0,96,10.0,5.0,5940.0,857.0,10.6,4.05,475.0,85.7,527.0,149.0,17.8,174000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(116,'WB 300',48.12,61.3,300.0,200.0,7.4,10.0,96,11.0,5.5,9820.0,990.0,12.6,4.01,654.0,99.0,731.0,171.0,24.7,280000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(117,'WB 350',56.89,72.4,350.0,200.0,8.0,11.4,96,12.0,6.0,15500.0,1170.0,14.6,4.02,887.0,117.0,995.0,200.0,35.6,435000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(118,'WB 400',66.71,85.0,400.0,200.0,8.6,13.0,96,13.0,6.5,23400.0,1380.0,16.6,4.04,1170.0,138.0,1320.0,234.0,50.6,648000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(119,'WB 450',79.52,101.0,450.0,200.0,9.2,15.4,96,15.0,7.0,35100.0,1700.0,18.6,4.1,1560.0,170.0,1760.0,284.0,78.7,969000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(120,'WB 500',95.12,121.0,500.0,250.0,9.9,14.7,96,15.0,7.5,52200.0,2980.0,20.7,4.96,2090.0,239.0,2350.0,406.0,94.3,2250000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(121,'WB 550',112.48,143.0,550.0,250.0,10.5,17.6,96,16.0,8.0,74900.0,3740.0,22.8,5.1,2720.0,299.0,3060.0,500.0,145.0,3240000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(122,'WB 600',133.7,170.0,600.0,250.0,11.2,21.3,96,17.0,8.5,106000.0,4700.0,24.9,5.25,3540.0,376.0,3980.0,619.0,234.0,4640000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(123,'WB 600',145.06,184.0,600.0,250.0,11.8,23.6,96,18.0,9.0,115000.0,5290.0,25.0,5.35,3850.0,423.0,4340.0,692.0,305.0,5099999.9999999996447,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(124,'WPB 100 X 100 X 12.24',12.24,15.5,91.0,100.0,4.2,5.5,90,12.0,0.0,236.0,92.0,3.89,2.43,51.9,18.4,58.3,28.4,2.32,1670.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(125,'WPB 100 X 100 X 16.67',16.67,21.2,96.0,100.0,5.0,8.0,90,12.0,0.0,349.0,133.0,4.05,2.51,72.7,26.7,83.0,41.1,5.28,2580.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(126,'WPB 100 X 100 X 20.44',20.44,26.0,100.0,100.0,6.0,10.0,90,12.0,0.0,449.0,167.0,4.15,2.53,89.9,33.4,104.0,51.4,9.33,3370.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(127,'WPB 100 X 100 X 41.79',41.79,53.2,120.0,106.0,12.0,20.0,90,12.0,0.0,1140.0,399.0,4.63,2.73,190.0,75.3,235.0,116.0,67.2,9920.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(128,'WPB 120 X 120 X 14.56',14.56,18.5,109.0,120.0,4.2,5.5,90,12.0,0.0,413.0,158.0,4.72,2.92,75.8,26.4,84.1,40.6,2.59,4240.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(129,'WPB 120 X 120 X 19.89',19.89,25.3,114.0,120.0,5.0,8.0,90,12.0,0.0,606.0,230.0,4.89,3.01,106.0,38.4,119.0,58.8,6.04,6470.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(130,'WPB 120 X 120 X 26.7',26.7,34.0,120.0,120.0,6.5,11.0,90,12.0,0.0,864.0,317.0,5.04,3.05,144.0,52.9,165.0,80.9,13.9,9400.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(131,'WPB 120 X 120 X 52.13',52.13,66.4,140.0,126.0,12.5,21.0,90,12.0,0.0,2010.0,702.0,5.51,3.25,288.0,111.0,350.0,171.0,90.5,24700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(132,'WPB 140 X 140 X 18.08',18.08,23.0,128.0,140.0,4.3,6.0,90,12.0,0.0,719.0,274.0,5.59,3.45,112.0,39.2,123.0,59.9,3.43,10200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(133,'WPB 140 X 140 X 24.66',24.66,31.4,133.0,140.0,5.5,8.5,90,12.0,0.0,1030.0,389.0,5.73,3.52,155.0,55.6,173.0,84.8,8.1,15000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(134,'WPB 140 X 140 X 33.72',33.72,42.9,140.0,140.0,7.0,12.0,90,12.0,0.0,1500.0,549.0,5.92,3.57,215.0,78.5,245.0,119.0,20.1,22400.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(135,'WPB 140 X 140 X 63.24',63.24,80.5,160.0,146.0,13.0,22.0,90,12.0,0.0,3290.0,1140.0,6.39,3.76,411.0,156.0,493.0,240.0,118.0,54300.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(136,'WPB 150 X 150 X 23.5',23.5,29.9,152.0,152.0,5.8,6.8,90,12.0,0.0,1270.0,398.0,6.52,3.64,167.0,52.4,186.0,80.4,5.55,20900.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(137,'WPB 150 X 150 X 30.11',30.11,38.3,158.0,153.0,6.5,9.4,90,8.0,0.0,1760.0,561.0,6.77,3.82,222.0,73.4,248.0,111.0,10.6,30900.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(138,'WPB 150 X 150 X 36.97',36.97,47.0,162.0,154.0,8.0,11.5,90,8.0,0.0,2210.0,700.0,6.85,3.85,273.0,91.0,308.0,138.0,19.2,39600.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(139,'WPB 160 X 160 X 22.75',22.75,28.9,148.0,160.0,4.5,7.0,90,8.0,0.0,1220.0,478.0,6.5,4.06,165.0,59.7,181.0,90.5,4.54,23700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(140,'WPB 160 X 160 X 30.44',30.44,38.7,152.0,160.0,6.0,9.0,90,15.0,0.0,1670.0,615.0,6.56,3.98,220.0,76.9,245.0,117.0,12.1,31400.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(141,'WPB 160 X 160 X 42.59',42.59,54.2,160.0,160.0,8.0,13.0,90,15.0,0.0,2490.0,889.0,6.77,4.04,311.0,111.0,353.0,169.0,31.2,47900.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(142,'WPB 160 X 160 X 76.19',76.19,97.0,180.0,166.0,14.0,23.0,90,15.0,0.0,5090.0,1750.0,7.24,4.25,566.0,211.0,674.0,325.0,160.0,108000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(143,'WPB 180 X 180 X 28.68',28.68,36.5,167.0,180.0,5.0,7.5,90,15.0,0.0,1960.0,729.0,7.33,4.47,235.0,81.1,258.0,123.0,8.32,46300.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(144,'WPB 180 X 180 X 35.52',35.52,45.2,171.0,180.0,6.0,9.5,90,15.0,0.0,2510.0,924.0,7.44,4.52,293.0,102.0,324.0,156.0,14.9,60200.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(145,'WPB 180 X 180 X 51.22',51.22,65.2,180.0,180.0,8.5,14.0,90,15.0,0.0,3830.0,1360.0,7.66,4.57,425.0,151.0,481.0,231.0,42.2,93700.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(146,'WPB 180 X180 X 88.9',88.9,113.0,200.0,186.0,14.5,24.0,90,15.0,0.0,7480.0,2580.0,8.12,4.77,748.0,277.0,883.0,425.0,201.0,199000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(147,'WPB 200 X 200 X 34.65',34.65,44.1,186.0,200.0,5.5,8.0,90,18.0,0.0,2940.0,1060.0,8.16,4.92,316.0,106.0,347.0,163.0,12.5,84400.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(148,'WPB 200 X 200 X 37.34',37.34,47.6,200.0,200.0,6.1,8.9,90,10.0,0.0,3628.0,1187.0,8.73,5.0,363.0,119.0,398.0,180.0,13.3,NULL,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(149,'WPB 200 X 200 X 42.26',42.26,53.8,190.0,200.0,6.5,10.0,90,18.0,0.0,3690.0,1330.0,8.28,4.98,388.0,133.0,429.0,203.0,21.0,108000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(150,'WPB 200 X 200 X 50.92',50.92,64.8,194.0,202.0,8.0,12.0,90,18.0,0.0,4530.0,1650.0,8.35,5.04,467.0,163.0,521.0,249.0,34.3,136000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(151,'WPB 200 X 200 X 61.3',61.3,78.0,200.0,200.0,9.0,15.0,90,18.0,0.0,5690.0,2000.0,8.54,5.06,569.0,200.0,642.0,305.0,59.7,171000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(152,'WPB 200 X 200 X 74.01',74.01,94.2,206.0,206.0,10.2,18.0,90,18.0,0.0,7170.0,2620.0,8.72,5.27,696.0,255.0,793.0,388.0,99.3,231000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(153,'WPB 200 X 200 X 83.52',83.52,106.0,209.0,209.0,13.0,19.5,90,18.0,0.0,8050.0,2970.0,8.7,5.28,771.0,284.0,888.0,435.0,134.0,266000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(154,'WPB 200 X 200 X 103.06',103.06,131.0,220.0,206.0,15.0,25.0,90,18.0,0.0,10600.0,3650.0,9.0,5.27,967.0,354.0,1130.0,543.0,257.0,346000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(155,'WPB 220 X 220 X 40.4',40.4,51.4,205.0,220.0,6.0,8.5,90,18.0,0.0,4170.0,1510.0,9.0,5.41,406.0,137.0,445.0,209.0,15.5,145000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(156,'WPB 220 X 220 X 50.51',50.51,64.3,210.0,220.0,7.0,11.0,90,18.0,0.0,5400.0,1950.0,9.16,5.51,515.0,177.0,568.0,270.0,28.6,193000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(157,'WPB 220 X 220 X 71.47',71.47,91.0,220.0,220.0,9.5,16.0,90,18.0,0.0,8090.0,2840.0,9.42,5.58,735.0,258.0,827.0,393.0,77.0,295000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(158,'WPB 220 X 220 X 115.61',115.61,147.0,226.0,226.0,15.5,26.0,90,18.0,0.0,12600.0,5010.0,9.28,5.83,1120.0,443.0,1310.0,677.0,311.0,500000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(159,'WPB 240 X 240 X 47.4',47.4,60.3,224.0,240.0,6.5,9.0,90,21.0,0.0,5830.0,2070.0,9.83,5.86,520.0,173.0,570.0,264.0,22.1,239000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(160,'WPB 240 X 240 X 60.32',60.32,76.8,230.0,240.0,7.5,12.0,90,21.0,0.0,7760.0,2760.0,10.0,6.0,675.0,230.0,744.0,351.0,42.1,328000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(161,'WPB 240 X 240 X 83.2',83.2,105.0,240.0,240.0,10.0,17.0,90,21.0,0.0,11200.0,3920.0,10.3,6.08,938.0,326.0,1050.0,498.0,103.0,486000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(162,'WPB 240 X 240 X 156.68',156.68,199.0,270.0,248.0,18.0,32.0,90,21.0,0.0,24200.0,8150.0,11.0,6.39,1790.0,657.0,2110.0,1000.0,626.0,1150000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(163,'WPB 250 X 250 X 67.22',67.22,85.6,247.0,252.0,11.0,11.1,90,24.0,0.0,9390.0,2960.0,10.4,5.89,760.0,235.0,851.0,364.0,51.3,411000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(164,'WPB 250 X 250 X 73.15',73.15,93.1,252.0,250.0,9.0,13.6,90,24.0,0.0,11000.0,3540.0,10.9,6.17,880.0,283.0,977.0,434.0,67.6,503000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(165,'WPB 250 X 250 X 85.04',85.04,108.0,253.0,255.0,14.0,14.1,90,24.0,0.0,12100.0,3910.0,10.5,6.0,961.0,306.0,1080.0,475.0,95.6,555000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(166,'WPB 250 X 250 X 97.04',97.04,123.0,260.0,256.0,12.7,17.6,90,24.0,0.0,15000.0,4930.0,11.0,6.31,1150.0,385.0,1300.0,591.0,140.0,722000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(167,'WPB 250 X 250 X 103.97',103.97,132.0,264.0,257.0,11.9,19.6,90,24.0,0.0,16700.0,5550.0,11.2,6.47,1270.0,432.0,1430.0,660.0,174.0,828000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(168,'WPB 250 X 250 X 117.58',117.58,149.0,269.0,259.0,13.5,22.1,90,24.0,0.0,19300.0,6410.0,11.3,6.54,1430.0,495.0,1630.0,757.0,244.0,975000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(169,'WPB 250 X 250 X 133.92',133.92,170.0,275.0,261.0,15.4,25.1,90,24.0,0.0,22500.0,7450.0,11.4,6.61,1640.0,571.0,1880.0,874.0,351.0,1160000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(170,'WPB 250 X 250 X 148.38',148.38,189.0,280.0,263.0,17.3,27.6,90,24.0,0.0,25400.0,8380.0,11.5,6.66,1810.0,637.0,2100.0,978.0,466.0,1330000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(171,'WPB 260 X 260 X 54.15',54.15,68.9,244.0,260.0,6.5,9.5,90,24.0,0.0,7980.0,2780.0,10.7,6.35,654.0,214.0,714.0,327.0,30.1,382000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(172,'WPB 260 X 260 X 68.16',68.16,86.8,250.0,260.0,7.5,12.5,90,24.0,0.0,10400.0,3660.0,10.9,6.5,836.0,282.0,919.0,430.0,54.2,516000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(173,'WPB 260 X 260 X 92.99',92.99,118.0,260.0,260.0,10.0,17.5,90,24.0,0.0,14900.0,5130.0,11.2,6.58,1140.0,394.0,1280.0,602.0,126.0,753000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(174,'WPB 260 X 260 X 114.4',114.4,145.0,268.0,262.0,12.5,21.5,90,24.0,0.0,18900.0,6450.0,11.3,6.65,1410.0,492.0,1590.0,752.0,224.0,978000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(175,'WPB 260 X 260 X 141.52',141.52,180.0,278.0,265.0,15.5,26.5,90,24.0,0.0,24300.0,8230.0,11.6,6.75,1750.0,621.0,2010.0,950.0,407.0,1290000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(176,'WPB 260 X 260 X 172.43',172.43,219.0,290.0,268.0,18.0,32.5,90,24.0,0.0,31300.0,10400.0,11.9,6.89,2150.0,779.0,2520.0,1190.0,720.0,1720000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(177,'WPB 280 X 280 X 61.26',61.26,78.0,264.0,280.0,7.0,10.0,90,24.0,0.0,10500.0,3660.0,11.6,6.85,799.0,261.0,873.0,399.0,35.5,590000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(178,'WPB 280 X 280 X 76.36',76.36,97.2,270.0,280.0,8.0,13.0,90,24.0,0.0,13600.0,4760.0,11.8,6.99,1010.0,340.0,1110.0,518.0,63.5,785000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(179,'WPB 280 X 280 X 188.54',188.54,240.0,310.0,288.0,18.5,33.0,90,24.0,0.0,39500.0,13100.0,12.8,7.4,2550.0,914.0,2960.0,1390.0,807.0,2520000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(180,'WPB 280 X 280 X 284.13',284.13,361.95,280.0,280.0,10.5,18.0,90,24.0,0.0,30682.9,9105.2,9.21,5.02,2191.6,650.4,2941.1,1406.8,146.0,1130000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(181,'WPB 300 X 300 X 69.8',69.8,88.9,283.0,300.0,7.5,10.5,90,27.0,0.0,13800.0,4730.0,12.4,7.29,975.0,315.0,1060.0,482.0,47.8,877000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(182,'WPB 300 X 300 X 88.34',88.34,112.0,290.0,300.0,8.5,14.0,90,27.0,0.0,18200.0,6300.0,12.7,7.48,1250.0,420.0,1380.0,641.0,87.8,1190000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(183,'WPB 300 X 300 X 100.85',100.85,128.0,294.0,300.0,10.0,16.0,90,27.0,0.0,21000.0,7210.0,12.8,7.49,1430.0,480.0,1580.0,733.0,124.0,1390000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(184,'WPB 300 X 300 X 117.03',117.03,149.0,300.0,300.0,11.0,19.0,90,27.0,0.0,25100.0,8560.0,12.9,7.57,1670.0,570.0,1860.0,870.0,189.0,1680000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(185,'WPB 300 X 300 X 237.92',237.92,303.0,340.0,310.0,21.0,39.0,90,27.0,0.0,59200.0,19400.0,13.9,8.0,3480.0,1250.0,4070.0,1910.0,1410.0,4380000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(186,'WPB 320 X 300 X 74.25',74.25,94.5,301.0,300.0,8.0,11.0,90,27.0,0.0,16400.0,4950.0,13.1,7.24,1090.0,330.0,1190.0,505.0,53.6,1040000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(187,'WPB 320 X 300 X 97.64',97.64,124.0,310.0,300.0,9.0,15.5,90,27.0,0.0,22900.0,6980.0,13.5,7.49,1470.0,465.0,1620.0,709.0,111.0,1510000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(188,'WPB 320 X 300 X 126.66',126.66,161.0,320.0,300.0,11.5,20.5,90,27.0,0.0,30800.0,9230.0,13.8,7.56,1920.0,615.0,2140.0,939.0,230.0,2060000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(189,'WPB 320 X 300 X 244.97',244.97,312.0,359.0,309.0,21.0,40.0,90,27.0,0.0,68100.0,19700.0,14.7,7.94,3790.0,1270.0,4430.0,1950.0,1500.0,5000000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(190,'WPB 340 X 300 X 78.9',78.9,100.0,320.0,300.0,8.5,11.5,90,27.0,0.0,19500.0,5180.0,13.9,7.18,1220.0,345.0,1340.0,529.0,60.1,1230000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(191,'WPB 340 X 300 X 104.78',104.78,133.0,330.0,300.0,9.5,16.5,90,27.0,0.0,27600.0,7430.0,14.4,7.46,1670.0,495.0,1850.0,755.0,131.0,1820000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(192,'WPB 340 X 300 X 134.16',134.16,170.0,340.0,300.0,12.0,21.5,90,27.0,0.0,36600.0,9680.0,14.6,7.53,2150.0,645.0,2400.0,985.0,262.0,2450000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(193,'WPB 340 X 300 X 290.64',290.64,315.0,377.0,309.0,21.0,40.0,90,27.0,0.0,76300.0,19700.0,15.5,7.9,4050.0,1270.0,4710.0,1950.0,1510.0,5580000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(194,'WPB 360 X 300 X 91.04',91.04,106.0,339.0,300.0,9.0,12.0,90,27.0,0.0,23000.0,5410.0,14.7,7.12,1350.0,360.0,1490.0,552.0,67.2,1440000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(195,'WPB 360 X 300 X 125.81',125.81,142.0,350.0,300.0,10.0,17.5,90,27.0,0.0,33000.0,7880.0,15.2,7.43,1890.0,525.0,2080.0,802.0,153.0,2170000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(196,'WPB 360 X 300 X 163.0',163.0,180.0,360.0,300.0,12.5,22.5,90,27.0,0.0,43100.0,10100.0,15.4,7.49,2390.0,676.0,2680.0,1030.0,298.0,2880000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(197,'WPB 360 X 300 X 250.27',250.27,318.0,395.0,308.0,21.0,40.0,90,27.0,0.0,84800.0,19500.0,16.3,7.82,4290.0,1260.0,4980.0,1940.0,1510.0,6130000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(198,'WPB 360 X 370 X 136.21',136.21,173.0,356.0,369.0,11.2,17.8,90,27.0,0.0,42100.0,14900.0,15.5,9.27,2360.0,808.0,2600.0,1220.0,192.0,4260000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(199,'WPB 360 X 370 X 150.87',150.87,192.0,360.0,370.0,12.3,19.8,90,27.0,0.0,47300.0,16700.0,15.6,9.33,2620.0,904.0,2900.0,1370.0,256.0,4830000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(200,'WPB 360 X 370 X 165.35',165.35,210.0,364.0,371.0,13.3,21.8,90,27.0,0.0,52500.0,18500.0,15.7,9.39,2880.0,1000.0,3200.0,1520.0,333.0,5430000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(201,'WPB 360 X 370 X 182.02',182.02,231.0,368.0,373.0,15.0,23.8,90,27.0,0.0,58200.0,20600.0,15.8,9.42,3160.0,1100.0,3530.0,1680.0,432.0,6090000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(202,'WPB 360 X 370 X 197.66',197.66,251.0,372.0,374.0,16.4,25.8,90,27.0,0.0,63900.0,22500.0,15.9,9.45,3430.0,1200.0,3850.0,1830.0,546.0,6740000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(203,'WPB 400 X 300 X 92.4',92.4,117.0,378.0,300.0,9.5,13.0,90,27.0,0.0,31200.0,5860.0,16.2,7.05,1650.0,390.0,1820.0,599.0,81.4,1940000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(204,'WPB 400 X 300 X 124.81',124.81,158.0,390.0,300.0,11.0,19.0,90,27.0,0.0,45000.0,8560.0,16.8,7.33,2310.0,570.0,2560.0,872.0,193.0,2940000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(205,'WPB 400 X 300 X 155.26',155.26,197.0,400.0,300.0,13.5,24.0,90,27.0,0.0,57600.0,10800.0,17.0,7.39,2880.0,721.0,3230.0,1100.0,361.0,3810000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(206,'WPB 400 X 300 X 255.74',255.74,325.0,432.0,307.0,21.0,40.0,90,27.0,0.0,104000.0,19300.0,17.8,7.7,4820.0,1250.0,5570.0,1930.0,1520.0,7410000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(207,'WPB 400 X 400 X 191.11',191.11,243.0,368.0,391.0,15.0,24.2,90,27.0,0.0,61500.0,24100.0,15.9,9.95,3340.0,1230.0,3730.0,1870.0,467.0,7120000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(208,'WPB 400 X 400 X 219.67',219.67,279.0,375.0,394.0,17.3,27.7,90,27.0,0.0,72100.0,28200.0,16.0,10.0,3840.0,1430.0,4320.0,2180.0,691.0,8510000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(209,'WPB 400 X 400 X 239.62',239.62,305.0,380.0,395.0,18.9,30.2,90,27.0,0.0,79700.0,31000.0,16.1,10.0,4190.0,1570.0,4750.0,2390.0,887.0,9480000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(210,'WPB 450 X 300 X 99.75',99.75,127.0,425.0,300.0,10.0,13.5,90,27.0,0.0,41800.0,6080.0,18.1,6.92,1970.0,405.0,2180.0,624.0,91.4,2570000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(211,'WPB 450 X 300 X 139.76',139.76,178.0,440.0,300.0,11.5,21.0,90,27.0,0.0,63700.0,9460.0,18.9,7.29,2890.0,631.0,3210.0,965.0,250.0,4140000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(212,'WPB 450 X 300 X 171.12',171.12,217.0,450.0,300.0,14.0,26.0,90,27.0,0.0,79800.0,11700.0,19.1,7.33,3550.0,781.0,3980.0,1190.0,448.0,5250000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(213,'WPB 450 X 300 X 263.33',263.33,335.0,478.0,307.0,21.0,40.0,90,27.0,0.0,131000.0,19300.0,19.7,7.59,5500.0,1250.0,6330.0,1930.0,1530.0,9250000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(214,'WPB 500 X 300 X 107.46',107.46,136.0,472.0,300.0,10.5,14.0,90,27.0,0.0,54600.0,6310.0,19.9,6.79,2310.0,420.0,2570.0,649.0,102.0,3299999.9999999998223,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(215,'WPB 500 X 300 X 129.78',129.78,165.0,480.0,300.0,11.5,18.0,90,27.0,0.0,68900.0,8110.0,20.4,7.0,2870.0,541.0,3190.0,832.0,179.0,4320000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(216,'WPB 500 X 300 X 155.08',155.08,197.0,490.0,300.0,12.0,23.0,90,27.0,0.0,86900.0,10300.0,20.9,7.24,3540.0,691.0,3940.0,1050.0,317.0,5640000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(217,'WPB 500 X 300 X 187.34',187.34,238.0,500.0,300.0,14.5,28.0,90,27.0,0.0,107000.0,12600.0,21.1,7.27,4280.0,841.0,4810.0,1290.0,548.0,7010000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(218,'WPB 500 X 300 X 270.28',270.28,344.0,524.0,306.0,21.0,40.0,90,27.0,0.0,161000.0,19100.0,21.6,7.45,6180.0,1250.0,7090.0,1930.0,1540.0,11100000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(219,'WPB 550 X 300 X 119.99',119.99,152.0,522.0,300.0,11.5,15.0,90,27.0,0.0,72800.0,6760.0,21.8,6.65,2790.0,451.0,3120.0,698.0,126.0,4330000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(220,'WPB 550 X 300 X 166.24',166.24,211.0,540.0,300.0,12.5,24.0,90,27.0,0.0,111000.0,10800.0,22.9,7.14,4140.0,721.0,4620.0,1100.0,360.0,7180000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(221,'WPB 550 X 300 X 199.44',199.44,254.0,550.0,300.0,15.0,29.0,90,27.0,0.0,136000.0,13000.0,23.1,7.17,4970.0,871.0,5590.0,1340.0,610.0,8850000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(222,'WPB 550 X 300 X 278.19',278.19,354.0,572.0,306.0,21.0,40.0,90,27.0,0.0,197000.0,19100.0,23.6,7.35,6920.0,1250.0,7930.0,1930.0,1550.0,13500000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(223,'WPB 600 X300 X 128.79',128.79,164.0,571.0,300.0,12.0,15.5,90,27.0,0.0,91800.0,6990.0,23.6,6.52,3210.0,466.0,3620.0,724.0,141.0,5380000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(224,'WPB 600 X 300 X 177.78',177.78,226.0,590.0,300.0,13.0,25.0,90,27.0,0.0,141000.0,11200.0,24.9,7.05,4780.0,751.0,5350.0,1150.0,407.0,8970000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(225,'WPB 600 X 300 X 211.92',211.92,269.0,600.0,300.0,15.5,30.0,90,27.0,0.0,171000.0,13500.0,25.1,7.08,5700.0,902.0,6420.0,1390.0,677.0,10900000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(226,'WPB 600 X 300 X 285.48',285.48,363.0,620.0,305.0,21.0,40.0,90,27.0,0.0,237000.0,18900.0,25.5,7.22,7650.0,1240.0,8770.0,1930.0,1560.0,15900000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(227,'WPB 650 X 300 X 137.98',137.98,175.0,620.0,300.0,12.5,16.0,90,27.0,0.0,113000.0,7220.0,25.4,6.41,3670.0,481.0,4150.0,750.0,158.0,6560000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(228,'WPB 650 X 300 X 189.69',189.69,241.0,640.0,300.0,13.5,26.0,90,27.0,0.0,175000.0,11700.0,26.9,6.96,5470.0,781.0,6130.0,1200.0,457.0,11000000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(229,'WPB 650 X 300 X 224.78',224.78,286.0,650.0,300.0,16.0,31.0,90,27.0,0.0,210000.0,13900.0,27.1,6.98,6480.0,932.0,7310.0,1440.0,749.0,13300000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(230,'WPB 650 X 300 X 293.39',293.39,373.0,668.0,305.0,21.0,40.0,90,27.0,0.0,281000.0,18900.0,27.4,7.12,8430.0,1240.0,9650.0,1930.0,1580.0,18600000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(231,'WPB 700 X 300 X 149.89',149.89,190.0,670.0,300.0,13.0,17.0,90,27.0,0.0,142000.0,7670.0,27.3,6.33,4260.0,511.0,4840.0,799.0,186.0,8150000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(232,'WPB 700 X 300 X 204.48',204.48,260.0,690.0,300.0,14.5,27.0,90,27.0,0.0,215000.0,12100.0,28.7,6.83,6240.0,811.0,7030.0,1250.0,521.0,13300000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(233,'WPB 700 X 300 X 240.51',240.51,306.0,700.0,300.0,17.0,32.0,90,27.0,0.0,256000.0,14400.0,28.9,6.86,7330.0,962.0,8320.0,1490.0,839.0,16000000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(234,'WPB 700 X 300 X 300.68',300.68,383.0,716.0,304.0,21.0,40.0,90,27.0,0.0,329000.0,18700.0,29.3,7.0,9190.0,1230.0,10500.0,1920.0,1590.0,21299999.999999998934,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(235,'WPB 800 X 300 X 171.52',171.52,218.0,770.0,300.0,14.0,18.0,90,30.0,0.0,208000.0,8130.0,30.9,6.1,5420.0,542.0,6220.0,856.0,243.0,11399999.999999999023,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(236,'WPB 800 X 300 X 224.38',224.38,285.0,790.0,300.0,15.0,28.0,90,30.0,0.0,303000.0,12600.0,32.5,6.65,7680.0,842.0,8690.0,1310.0,608.0,18200000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(237,'WPB 800 X 300 X 262.34',262.34,334.0,800.0,300.0,17.5,33.0,90,30.0,0.0,359000.0,14900.0,32.7,6.67,8970.0,993.0,10200.0,1550.0,958.0,21800000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(238,'WPB 800 X 300 X 317.36',317.36,404.0,814.0,303.0,21.0,40.0,90,30.0,0.0,442000.0,18600.0,33.0,6.78,10800.0,1220.0,12400.0,1930.0,1650.0,27700000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(239,'WPB 800 X 300 X 179.9',179.9,229.0,835.0,292.0,14.0,18.8,90,30.0,0.0,253000.0,7830.0,33.2,5.84,6080.0,536.0,7000.0,851.0,264.0,12900000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(240,'WPB 850 X 300 X 195.74',195.74,249.0,840.0,292.0,14.7,21.3,90,30.0,0.0,282000.0,8870.0,33.6,5.96,6720.0,608.0,7730.0,961.0,343.0,14799999.999999999822,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(241,'WPB 850 X 300 X 214.25',214.25,272.0,846.0,293.0,15.4,24.3,90,30.0,0.0,317000.0,10200.0,34.1,6.12,7500.0,698.0,8600.0,1100.0,459.0,17099999.999999999644,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(242,'WPB 850 X 300 X 230.56',230.56,293.0,851.0,294.0,16.1,26.8,90,30.0,0.0,347000.0,11300.0,34.4,6.23,8160.0,775.0,9350.0,1220.0,579.0,19199999.999999999289,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(243,'WPB 850 X 300 X 253.69',253.69,323.0,859.0,292.0,17.0,30.8,90,30.0,0.0,392000.0,12800.0,34.8,6.3,9130.0,879.0,10400.0,1380.0,802.0,21899999.999999999467,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(244,'WPB 900 X 300 X 198.01',198.01,252.0,870.0,300.0,15.0,20.0,90,30.0,0.0,301000.0,9040.0,34.5,5.98,6920.0,602.0,7990.0,957.0,321.0,16200000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(245,'WPB 900 X 300 X 251.62',251.62,320.0,890.0,300.0,16.0,30.0,90,30.0,0.0,422000.0,13500.0,36.2,6.5,9480.0,903.0,10800.0,1410.0,749.0,24900000.0,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(246,'WPB 900 X 300 X 291.46',291.46,371.0,900.0,300.0,18.5,35.0,90,30.0,0.0,494000.0,15800.0,36.4,6.52,10900.0,1050.0,12500.0,1650.0,1150.0,29399999.999999998578,'IS808_Rev',NULL); +INSERT INTO Beams VALUES(247,'UB 1016 x 305 x 222',222.0,282.8,970.3,300.0,16.0,21.1,90,30.0,0.0,407961.0,9534.0,38.0,5.8,8409.0,636.0,9807.0,1020.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(248,'UB 1016 x 305 x 249',248.7,316.9,980.2,300.0,16.5,26.0,90,30.0,0.0,481305.0,11743.0,39.0,6.1,9821.0,783.0,11350.0,1245.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(249,'UB 1016 x 305 x 272',272.3,346.9,990.1,300.0,16.5,31.0,90,30.0,0.0,553974.0,13993.0,40.0,6.4,11190.0,933.0,12826.0,1470.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(250,'UB 1016 x 305 x 314',314.3,400.4,1000.0,300.0,19.1,35.9,90,30.0,0.0,644211.0,16219.0,40.1,6.4,12884.0,1081.0,14851.0,1713.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(251,'UB 1016 x 305 x 349',349.4,445.2,1008.1,302.0,21.1,40.0,90,30.0,0.0,723131.0,18446.0,40.3,6.4,14346.0,1222.0,16592.0,1941.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(252,'UB 1016 x 305 x 393',392.7,500.2,1016.0,303.0,24.4,43.9,90,30.0,0.0,807688.0,20480.0,40.2,6.4,15899.0,1352.0,18539.0,2168.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(253,'UB 1016 x 305 x 437',436.9,556.6,1025.9,305.4,26.9,49.0,90,30.0,0.0,909906.0,23430.0,40.4,6.5,17739.0,1534.0,20762.0,2469.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(254,'UB 1016 x 305 x 487',486.6,619.9,1036.1,308.5,30.0,54.1,90,30.0,0.0,1021420.0,26703.0,40.6,6.6,19717.0,1731.0,23200.0,2800.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(255,'UB 127 x 76 x 13',13.0,16.5,127.0,76.0,4.0,7.6,90,7.6,0.0,473.0,55.7,5.4,1.8,75.0,15.0,84.2,22.6,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(256,'UB 152 x 89 x 16',16.0,20.3,152.0,88.7,4.5,7.7,90,7.6,0.0,834.0,89.7,6.4,2.1,109.0,20.0,123.0,31.2,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(257,'UB 178 x 102 x 19',19.0,24.3,178.0,101.2,4.8,7.9,90,7.6,0.0,1356.0,137.0,7.5,2.4,153.0,27.0,171.0,41.6,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(258,'UB 203 x 102 x 23',23.1,29.4,203.0,101.8,5.4,9.3,90,7.6,0.0,2105.0,164.0,8.5,2.4,207.0,32.0,234.0,49.8,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(259,'UB 203 x 133 x 25',25.1,32.0,203.0,133.2,5.7,7.8,90,7.6,0.0,2340.0,308.0,8.6,3.1,230.0,46.0,258.0,70.9,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(260,'UB 203 x 133 x 30',30.0,38.2,207.0,133.9,6.4,9.6,90,7.6,0.0,2896.0,385.0,8.7,3.2,280.0,57.0,314.0,88.2,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(261,'UB 254 x 102 x 22',22.0,28.0,254.0,101.6,5.7,6.8,90,7.6,0.0,2841.0,119.0,10.1,2.1,224.0,23.0,259.0,37.3,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(262,'UB 254 x 102 x 25',25.2,32.0,257.0,101.9,6.0,8.4,90,7.6,0.0,3415.0,149.0,10.3,2.2,266.0,29.0,306.0,46.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(263,'UB 254 x 102 x 28',28.3,36.1,260.0,102.2,6.3,10.0,90,7.6,0.0,4005.0,178.0,10.5,2.2,308.0,35.0,353.0,54.8,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(264,'UB 254 x 146 x 31',31.1,39.7,251.0,146.1,6.0,8.6,90,7.6,0.0,4413.0,447.0,10.5,3.4,351.0,61.0,393.0,94.1,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(265,'UB 254 x 146 x 37',37.0,47.2,256.0,146.4,6.3,10.9,90,7.6,0.0,5537.0,571.0,10.8,3.5,433.0,78.0,483.0,119.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(266,'UB 254 x 146 x 43',43.0,54.8,260.0,147.3,7.2,12.7,90,7.6,0.0,6544.0,677.0,10.9,3.5,504.0,92.0,566.0,141.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(267,'UB 305 x 102 x 25',24.8,31.6,305.0,101.6,5.8,7.0,90,7.6,0.0,4455.0,123.0,11.9,2.0,292.0,24.0,342.0,38.8,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(268,'UB 305 x 102 x 28',28.2,35.9,309.0,101.8,6.0,8.8,90,7.6,0.0,5366.0,155.0,12.2,2.1,348.0,31.0,403.0,48.5,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(269,'UB 305 x 102 x 33',32.8,41.8,313.0,102.4,6.6,10.8,90,7.6,0.0,6501.0,194.0,12.5,2.2,416.0,38.0,481.0,60.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(270,'UB 305 x 127 x 37',37.0,47.2,304.0,123.4,7.1,10.7,90,8.9,0.0,7171.0,336.0,12.3,2.7,471.0,54.0,539.0,85.4,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(271,'UB 305 x 127 x 42',41.9,53.4,307.0,124.3,8.0,12.1,90,8.9,0.0,8196.0,389.0,12.4,2.7,534.0,63.0,614.0,98.4,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(272,'UB 305 x 127 x 48',48.1,61.2,311.0,125.3,9.0,14.0,90,8.9,0.0,9575.0,461.0,12.5,2.7,616.0,74.0,711.0,116.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(273,'UB 305 x 165 x 40',40.3,51.3,303.0,165.0,6.0,10.2,90,8.9,0.0,8503.0,764.0,12.9,3.9,560.0,93.0,623.0,142.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(274,'UB 305 x 165 x 46',46.1,58.7,307.0,165.7,6.7,11.8,90,8.9,0.0,9899.0,896.0,13.0,3.9,646.0,108.0,720.0,166.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(275,'UB 305 x 165 x 54',54.0,68.8,310.0,166.9,7.9,13.7,90,8.9,0.0,11696.0,1063.0,13.0,3.9,754.0,127.0,846.0,196.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(276,'UB 356 x 127 x 33',33.1,42.1,349.0,125.4,6.0,8.5,90,10.2,0.0,8249.0,280.0,14.0,2.6,473.0,45.0,543.0,70.3,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(277,'UB 356 x 127 x 39',39.1,49.8,353.0,126.0,6.6,10.7,90,10.2,0.0,10172.0,358.0,14.3,2.7,576.0,57.0,659.0,89.1,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(278,'UB 356 x 171 x 45',45.0,57.3,351.0,171.1,7.0,9.7,90,10.2,0.0,12066.0,811.0,14.5,3.8,687.0,95.0,775.0,147.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(279,'UB 356 x 171 x 51',51.0,64.9,355.0,171.5,7.4,11.5,90,10.2,0.0,14136.0,968.0,14.8,3.9,796.0,113.0,896.0,174.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(280,'UB 356 x 171 x 57',57.0,72.6,358.0,172.2,8.1,13.0,90,10.2,0.0,16038.0,1108.0,14.9,3.9,896.0,129.0,1010.0,199.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(281,'UB 356 x 171 x 67',67.1,85.5,363.0,173.2,9.1,15.7,90,10.2,0.0,19463.0,1362.0,15.1,4.0,1071.0,157.0,1211.0,243.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(282,'UB 406 x 140 x 39',39.0,49.7,398.0,141.8,6.4,8.6,90,10.2,0.0,12508.0,410.0,15.9,2.9,629.0,58.0,724.0,91.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(283,'UB 406 x 140 x 46',46.0,58.6,403.0,142.2,6.8,11.2,90,10.2,0.0,15685.0,538.0,16.4,3.0,778.0,76.0,888.0,118.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(284,'UB 406 x 178 x 54',54.1,69.0,403.0,177.7,7.7,10.9,90,10.2,0.0,18722.0,1021.0,16.5,3.8,930.0,115.0,1055.0,178.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(285,'UB 406 x 178 x 60',60.1,76.5,406.0,177.9,7.9,12.8,90,10.2,0.0,21596.0,1203.0,16.8,4.0,1063.0,135.0,1199.0,209.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(286,'UB 406 x 178 x 67',67.1,85.5,409.0,178.8,8.8,14.3,90,10.2,0.0,24331.0,1365.0,16.9,4.0,1189.0,153.0,1346.0,237.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(287,'UB 406 x 178 x 74',74.2,94.5,413.0,179.5,9.5,16.0,90,10.2,0.0,27310.0,1545.0,17.0,4.0,1323.0,172.0,1501.0,267.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(288,'UB 457 x 152 x 52',52.3,66.6,450.0,152.4,7.6,10.9,90,10.2,0.0,21369.0,645.0,17.9,3.1,950.0,85.0,1096.0,133.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(289,'UB 457 x 152 x 60',59.8,76.2,455.0,152.9,8.1,13.3,90,10.2,0.0,25500.0,794.0,18.3,3.2,1122.0,104.0,1287.0,163.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(290,'UB 457 x 152 x 67',67.2,85.6,458.0,153.8,9.0,15.0,90,10.2,0.0,28927.0,912.0,18.4,3.3,1263.0,119.0,1453.0,187.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(291,'UB 457 x 152 x 74',74.2,94.5,462.0,154.4,9.6,17.0,90,10.2,0.0,32674.0,1046.0,18.6,3.3,1414.0,136.0,1627.0,213.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(292,'UB 457 x 152 x 82',82.1,104.5,466.0,155.3,10.5,18.9,90,10.2,0.0,36589.0,1184.0,18.7,3.4,1571.0,153.0,1811.0,240.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(293,'UB 457 x 191 x 67',67.1,85.5,453.0,189.9,8.5,12.7,90,10.2,0.0,29380.0,1452.0,18.5,4.1,1296.0,153.0,1471.0,237.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(294,'UB 457 x 191 x 74',74.3,94.6,457.0,190.4,9.0,14.5,90,10.2,0.0,33319.0,1671.0,18.8,4.2,1458.0,176.0,1653.0,272.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(295,'UB 457 x 191 x 82',82.0,104.5,460.0,191.3,9.9,16.0,90,10.2,0.0,37051.0,1871.0,18.8,4.2,1611.0,196.0,1831.0,304.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(296,'UB 457 x 191 x 89',89.3,113.8,463.0,191.9,10.5,17.7,90,10.2,0.0,41015.0,2089.0,19.0,4.3,1770.0,218.0,2014.0,338.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(297,'UB 457 x 191 x 98',98.3,125.3,467.0,192.8,11.4,19.6,90,10.2,0.0,45727.0,2347.0,19.1,4.3,1957.0,243.0,2232.0,379.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(298,'UB 533 x 210 x 101',101.0,128.7,537.0,210.0,10.8,17.4,90,12.7,0.0,61519.0,2691.0,21.9,4.6,2292.0,256.0,2612.0,399.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(299,'UB 533 x 210 x 109',109.0,138.9,540.0,210.8,11.6,18.8,90,12.7,0.0,66822.0,2942.0,21.9,4.6,2477.0,279.0,2828.0,436.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(300,'UB 533 x 210 x 122',122.0,155.4,545.0,211.9,12.7,21.3,90,12.7,0.0,76043.0,3387.0,22.1,4.7,2793.0,320.0,3196.0,500.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(301,'UB 533 x 210 x 82',82.2,104.7,528.0,208.8,9.6,13.2,90,12.7,0.0,47539.0,2007.0,21.3,4.4,1800.0,192.0,2059.0,300.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(302,'UB 533 x 210 x 92',92.1,117.4,533.0,209.3,10.1,15.6,90,12.7,0.0,55227.0,2389.0,21.7,4.5,2072.0,228.0,2360.0,356.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(303,'UB 610 x 229 x 101',101.2,128.9,603.0,227.6,10.5,14.8,90,12.7,0.0,75780.0,2914.0,24.2,4.8,2515.0,256.0,2881.0,400.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(304,'UB 610 x 229 x 113',113.0,143.9,608.0,228.2,11.1,17.3,90,12.7,0.0,87318.0,3433.0,24.6,4.9,2874.0,301.0,3281.0,469.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(305,'UB 610 x 229 x 125',125.1,159.3,612.0,229.0,11.9,19.6,90,12.7,0.0,98610.0,3932.0,24.9,5.0,3221.0,343.0,3676.0,535.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(306,'UB 610 x 229 x 140',139.9,178.2,617.0,230.2,13.1,22.1,90,12.7,0.0,111777.0,4505.0,25.0,5.0,3622.0,391.0,4142.0,611.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(307,'UB 610 x 305 x 149',149.2,190.0,612.0,304.8,11.8,19.7,90,16.5,0.0,125876.0,9306.0,25.7,7.0,4111.0,611.0,4594.0,937.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(308,'UB 610 x 305 x 179',179.0,228.1,620.0,307.1,14.1,23.6,90,16.5,0.0,153024.0,11407.0,25.9,7.1,4935.0,743.0,5547.0,1144.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(309,'UB 610 x 305 x 238',238.1,303.3,636.0,311.4,18.4,31.4,90,16.5,0.0,209471.0,15835.0,26.3,7.2,6589.0,1017.0,7486.0,1574.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(310,'UB 686 x 254 x 125',125.2,159.5,678.0,253.0,11.7,16.2,90,15.2,0.0,117992.0,4382.0,27.2,5.2,3481.0,346.0,3994.0,542.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(311,'UB 686 x 254 x 140',140.1,178.4,684.0,253.7,12.4,19.0,90,15.2,0.0,136267.0,5182.0,27.6,5.4,3987.0,409.0,4558.0,638.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(312,'UB 686 x 254 x 152',152.4,194.1,688.0,254.5,13.2,21.0,90,15.2,0.0,150355.0,5783.0,27.8,5.5,4374.0,454.0,5000.0,710.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(313,'UB 686 x 254 x 170',170.2,216.8,693.0,255.8,14.5,23.7,90,15.2,0.0,170326.0,6629.0,28.0,5.5,4916.0,518.0,5631.0,811.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(314,'UB 762 x 267 x 134',133.9,170.6,750.0,264.4,12.0,15.5,90,16.5,0.0,150692.0,4786.0,29.7,5.3,4018.0,362.0,4644.0,570.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(315,'UB 762 x 267 x 147',146.9,187.2,754.0,265.2,12.8,17.5,90,16.5,0.0,168501.0,5454.0,30.0,5.4,4470.0,411.0,5156.0,647.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(316,'UB 762 x 267 x 173',173.0,220.4,762.0,266.7,14.3,21.6,90,16.5,0.0,205282.0,6848.0,30.5,5.6,5387.0,514.0,6198.0,807.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(317,'UB 762 x 267 x 197',196.8,250.6,770.0,268.0,15.6,25.4,90,16.5,0.0,239957.0,8173.0,30.9,5.7,6234.0,610.0,7167.0,959.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(318,'UB 914 x 305 x 201',200.9,255.9,903.0,303.3,15.1,20.2,90,19.1,0.0,325254.0,9420.0,35.7,6.1,7204.0,621.0,8351.0,982.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(319,'UB 914 x 305 x 224',224.2,285.6,910.4,304.1,15.9,23.9,90,19.1,0.0,376413.0,11233.0,36.3,6.3,8269.0,739.0,9535.0,1163.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(320,'UB 914 x 305 x 253',253.4,322.8,918.4,305.5,17.3,27.9,90,19.1,0.0,436304.0,13298.0,36.8,6.4,9501.0,871.0,10942.0,1371.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(321,'UB 914 x 305 x 289',289.1,368.3,926.6,307.7,19.5,32.0,90,19.1,0.0,504187.0,15594.0,37.0,6.5,10883.0,1014.0,12570.0,1601.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(322,'UB 914 x 419 x 343',343.3,437.3,911.8,418.5,19.4,32.0,90,24.1,0.0,625779.0,39149.0,37.8,9.5,13726.0,1871.0,15477.0,2890.0,NULL,NULL,'',NULL); +INSERT INTO Beams VALUES(323,'UB 914 x 419 x 388',388.0,494.2,921.0,420.5,21.4,36.6,90,24.1,0.0,719635.0,45431.0,38.2,9.6,15627.0,2161.0,17665.0,3341.0,NULL,NULL,'',NULL); +CREATE TABLE IF NOT EXISTS "Channels" ( + "Id" INTEGER, + "Designation" VARCHAR(50), + "Mass" REAL(10 , 2), + "Area" REAL(10 , 2), + "D" INTEGER(50), + "B" INTEGER(50), + "tw" REAL(10 , 2), + "T" REAL(10 , 2), + "FlangeSlope" INTEGER, + "R1" REAL(10 , 2), + "R2" REAL(10 , 2), + "Cy" REAL(10 , 2), + "Iz" REAL(10 , 2), + "Iy" REAL(10 , 2), + "rz" REAL(10 , 2), + "ry" REAL(10 , 2), + "Zz" REAL(10 , 2), + "Zy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL, + "It" REAL(10 , 2), + "Iw" REAL(10 , 2), + "Source" VARCHAR(100), + "Type" VARCHAR(100), + PRIMARY KEY("Id") +); +INSERT INTO Channels VALUES(1,'MC 75',7.14,9.08,75,40,4.8,7.5,96,8.5,2.4,1.32,78.2,12.7,2.94,1.18,20.9,4.8,25.0,9.0,1.59,132.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(2,'MC 100',9.56,12.1,100,50,5.0,7.7,96,9.0,2.4,1.54,191.0,26.3,3.97,1.47,38.4,7.6,45.2,14.8,2.25,512.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(3,'MC 125',13.1,16.6,125,65,5.3,8.2,96,9.5,2.4,1.95,424.0,60.3,5.05,1.9,67.9,13.3,78.9,26.0,3.59,1900.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(4,'MC 125*',13.7,17.4,125,66,6.0,8.1,96,9.5,2.4,1.92,433.0,63.7,4.98,1.91,69.4,13.6,81.2,27.1,3.9,2030.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(5,'MC 150',16.8,21.3,150,75,5.7,9.0,96,10.0,2.4,2.2,786.0,102.0,6.08,2.19,104.0,19.3,121.0,38.1,5.45,4700.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(6,'MC 150*',17.7,22.5,150,76,6.5,9.0,96,10.0,2.4,2.17,810.0,108.0,6.0,2.2,108.0,20.0,126.0,40.0,6.07,5060.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(7,'MC 175',19.6,24.8,175,75,6.0,10.2,96,10.5,3.2,2.19,1230.0,120.0,7.04,2.2,141.0,22.7,163.0,44.7,7.49,7450.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(8,'MC 175*',22.7,27.3,175,76,7.5,10.2,96,10.5,3.2,2.14,1290.0,130.0,6.87,2.18,147.0,23.7,174.0,47.4,9.01,8250.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(9,'MC 200',22.3,28.4,200,75,6.2,11.4,96,11.0,3.2,2.2,1820.0,139.0,8.02,2.21,182.0,26.2,212.0,51.2,9.89,11000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(10,'MC 200*',24.3,30.9,200,76,7.5,11.4,96,11.0,3.2,2.12,1900.0,149.0,7.85,2.2,190.0,27.3,224.0,53.8,11.4,12100.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(11,'MC 225',26.1,33.2,225,80,6.5,12.4,96,12.0,3.2,2.31,2700.0,185.0,9.02,2.36,240.0,32.7,279.0,63.8,13.3,18700.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(12,'MC 225*',30.7,38.7,225,82,9.0,12.4,96,12.0,3.2,2.22,2920.0,210.0,8.69,2.33,260.0,35.1,309.0,68.6,17.6,22000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(13,'MC 250',30.6,38.9,250,80,7.2,14.1,96,12.0,3.2,2.3,3820.0,218.0,9.92,2.37,306.0,38.2,358.0,74.2,18.9,26800.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(14,'MC 250*',34.2,43.4,250,82,9.0,14.1,96,12.0,3.2,2.23,4060.0,242.0,9.68,2.36,325.0,40.7,386.0,78.7,22.8,30600.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(15,'MC 250*',38.1,48.1,250,83,11.0,14.1,96,12.0,3.2,2.19,4280.0,258.0,9.44,2.32,342.0,42.1,414.0,80.8,28.5,33800.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(16,'MC 300',36.3,46.2,300,90,7.8,13.6,96,13.0,3.2,2.35,6400.0,311.0,11.7,2.59,427.0,46.8,501.0,91.9,21.7,57500.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(17,'MC 300*',41.5,52.7,300,92,10.0,13.6,96,13.0,3.2,2.26,6880.0,344.0,11.4,2.55,458.0,49.6,549.0,96.3,28.1,66100.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(18,'MC 300*',46.2,58.4,300,93,12.0,13.6,96,13.0,3.2,2.22,7260.0,363.0,11.1,2.49,484.0,51.2,589.0,98.7,36.1,72300.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(19,'MC 350',42.7,54.3,350,100,8.3,13.5,96,14.0,4.8,2.44,10000.0,429.0,13.6,2.81,575.0,56.8,677.0,112.0,26.1,112000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(20,'MC 400',50.1,63.7,400,100,8.8,15.3,96,15.0,4.8,2.42,15100.0,504.0,15.4,2.81,758.0,66.5,898.0,129.0,36.1,170000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(21,'JC 100',5.8,7.41,100,45,3.0,5.1,91.5,6.0,2.0,1.4,123.0,14.6,4.09,1.4,24.8,4.7,28.4,8.8,0.51900000000000003907,264.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(22,'JC 125',7.9,10.0,125,50,3.0,6.6,91.5,6.0,2.4,1.64,269.0,25.1,5.17,1.58,43.1,7.5,49.1,13.6,1.07,701.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(23,'JC 150',9.9,12.6,150,55,3.6,6.9,91.5,7.0,2.4,1.67,471.0,37.4,6.1,1.72,62.9,9.8,72.1,18.1,1.47,1520.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(24,'JC 175',11.2,14.2,175,60,3.6,6.9,91.5,7.0,3.0,1.75,720.0,49.6,7.11,1.87,82.3,11.7,94.2,21.9,1.62,2780.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(25,'JC 200',14.0,17.7,200,70,4.1,7.1,91.5,8.0,3.2,1.97,1160.0,82.8,8.08,2.16,116.0,16.5,133.0,31.0,2.23,6150.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(26,'LC 75',5.7,7.26,75,40,3.7,6.0,91.5,6.0,2.0,1.35,65.9,11.3,3.01,1.25,17.6,4.3,20.6,7.7,0.72599999999999997868,110.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(27,'LC 100',7.9,10.0,100,50,4.0,6.4,91.5,6.0,2.0,1.62,164.0,24.4,4.05,1.56,32.9,7.2,38.1,13.3,1.11,434.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(28,'LC 125',10.7,13.6,125,65,4.4,6.6,91.5,7.0,2.4,2.04,356.0,56.3,5.11,2.03,57.1,12.6,65.4,23.4,1.68,1590.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(29,'LC (P) 125',11.3,14.3,125,65,4.6,7.0,96,7.0,2.4,1.87,370.0,50.6,5.08,1.88,59.2,10.9,68.3,22.0,2.27,1670.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(30,'LC 150',14.4,18.3,150,75,4.8,7.8,91.5,8.0,2.4,2.39,697.0,101.0,6.16,2.35,93.1,19.9,106.0,36.5,3.04,4120.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(31,'LC (P) 150',15.6,19.8,150,75,5.0,8.7,96,8.0,2.4,2.24,750.0,96.1,6.15,2.2,100.0,18.3,114.0,35.7,4.55,4450.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(32,'LC 175',17.6,22.4,175,75,5.1,9.5,91.5,8.0,3.2,2.4,1140.0,124.0,7.16,2.36,131.0,24.4,150.0,44.7,5.07,6830.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(33,'LC 200',20.6,26.2,200,75,5.5,10.8,91.5,8.5,3.2,2.36,1720.0,144.0,8.11,2.35,172.0,28.2,199.0,51.8,7.31,10300.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(34,'LC (P) 200',21.5,27.3,200,75,5.7,11.4,96,8.5,3.2,2.23,1790.0,136.0,8.09,2.23,179.0,25.9,207.0,50.2,9.13,10800.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(35,'LC 225',24.0,30.5,225,90,5.8,10.2,96,11.0,3.2,2.47,2550.0,207.0,9.14,2.6,226.0,31.8,260.0,64.2,9.3,22200.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(36,'LC 250',28.0,35.6,250,100,6.1,10.7,96,11.0,3.2,2.71,3690.0,295.0,10.1,2.88,295.0,40.6,338.0,82.5,12.0,39700.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(37,'LC 300',33.1,42.1,300,100,6.7,11.6,96,12.0,3.2,2.56,6050.0,344.0,11.9,2.86,403.0,46.3,467.0,94.2,15.6,66400.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(38,'LC (P) 300',33.1,42.1,300,90,7.0,12.5,96,12.0,3.2,2.32,5910.0,282.0,11.8,2.59,394.0,42.4,460.0,84.3,16.8,53000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(39,'LC 350',38.9,49.4,350,100,7.4,12.5,96,13.0,4.8,2.42,9310.0,391.0,13.7,2.81,532.0,51.6,623.0,103.0,20.3,103000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(40,'LC 400',45.8,58.2,400,100,8.0,14.0,96,14.0,4.8,2.37,13900.0,457.0,15.5,2.8,699.0,60.0,825.0,117.0,27.9,157000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(41,'MPC 75',7.14,9.1,75,40,4.8,7.5,90,8.5,4.5,1.38,78.6,13.7,2.94,1.23,21.0,5.2,25.2,9.5,1.48,132.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(42,'MPC 100',9.56,12.1,100,50,5.0,7.7,90,9.0,4.5,1.65,193.0,29.4,3.98,1.55,38.6,8.8,45.5,16.0,2.04,512.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(43,'MPC 125',13.1,16.7,125,65,5.5,8.1,90,9.5,5.0,2.14,426.0,69.8,5.04,2.04,68.2,15.9,79.3,29.1,3.14,1900.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(44,'MPC 125*',13.7,17.5,125,66,6.0,8.1,90,9.5,5.0,2.11,437.0,74.1,5.0,2.06,69.9,16.5,81.7,30.2,3.4,2030.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(45,'MPC 150',16.8,21.3,150,75,5.7,9.0,90,10.0,5.0,2.46,792.0,120.0,6.09,2.37,105.0,23.8,122.0,43.2,4.71,4700.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(46,'MPC 150*',17.7,22.5,150,76,6.5,9.0,90,10.0,5.0,2.4,817.0,128.0,6.02,2.38,109.0,24.7,126.0,45.1,5.25,5060.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(47,'MPC 175',19.6,24.9,175,75,6.0,10.2,90,10.5,6.0,2.39,1240.0,138.0,7.06,2.36,141.0,27.0,164.0,49.5,6.66,7450.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(48,'MPC 175*',21.7,27.6,175,77,7.5,10.2,90,10.5,6.0,2.32,1310.0,155.0,6.9,2.37,150.0,28.9,176.0,53.0,8.1,8550.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(49,'MPC 200',22.3,28.4,200,75,6.2,11.4,90,11.0,6.0,2.34,1830.0,157.0,8.03,2.35,183.0,30.5,213.0,55.9,8.99,11000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(50,'MPC 200*',24.3,30.9,200,76,7.5,11.4,90,11.0,6.5,2.26,1910.0,168.0,7.86,2.33,191.0,31.5,225.0,57.8,10.4,12100.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(51,'MPC 225',26.1,33.2,225,80,6.5,12.4,90,12.0,6.5,2.48,2710.0,208.0,9.03,2.5,241.0,37.9,280.0,69.5,12.1,18700.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(52,'MPC 225*',30.7,39.0,225,83,9.0,12.4,90,12.0,7.0,2.37,2960.0,244.0,8.72,2.51,263.0,41.3,312.0,75.3,16.2,22800.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(53,'MPC 250',30.6,38.9,250,80,7.2,14.1,90,12.0,7.0,2.44,3830.0,240.0,9.93,2.48,307.0,43.2,359.0,79.3,17.5,26800.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(54,'MPC 250*',34.2,43.4,250,82,9.0,14.1,90,12.0,7.0,2.36,4080.0,267.0,9.69,2.48,326.0,45.9,387.0,83.5,21.1,30600.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(55,'MPC 250*',38.1,48.6,250,84,11.0,14.1,90,12.0,7.0,2.31,4350.0,295.0,9.46,2.46,348.0,48.4,420.0,87.7,26.7,34900.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(56,'MPC 300',36.3,46.2,300,90,7.8,13.6,90,13.0,7.0,2.54,6420.0,351.0,11.7,2.76,428.0,54.4,502.0,99.1,19.8,57500.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(57,'MPC 300*',41.5,52.8,300,92,10.0,13.6,90,13.0,7.0,2.42,6910.0,390.0,11.4,2.72,460.0,57.5,551.0,103.0,25.7,66100.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(58,'MPC 300*',46.2,58.8,300,94,12.0,13.6,90,13.0,7.0,2.36,7360.0,424.0,11.1,2.69,490.0,60.3,596.0,108.0,33.5,74400.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(59,'MPC 350',42.7,54.3,350,100,8.3,13.5,90,14.0,8.0,2.65,10100.0,497.0,13.6,3.02,577.0,67.7,679.0,122.0,23.4,112000.0,'IS808_Rev',NULL); +INSERT INTO Channels VALUES(60,'MPC 400',50.1,63.8,400,100,8.8,15.3,90,15.0,8.0,2.6,15200.0,572.0,15.4,3.0,762.0,77.4,901.0,139.0,33.1,170000.0,'IS808_Rev',NULL); +CREATE TABLE IF NOT EXISTS "SHS" ( + "Id" INTEGER NOT NULL, + "Designation" VARCHAR, + "D" REAL(10 , 2), + "B" REAL(10 , 2), + "T" REAL(10 , 2), + "W" REAL(10 , 2), + "A" REAL(10 , 2), + "Izz" REAL(10 , 2), + "Iyy" REAL(10 , 2), + "Rzz" REAL(10 , 2), + "Ryy" REAL(10 , 2), + "Zzz" REAL(10 , 2), + "Zyy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "Source" VARCHAR(50), + PRIMARY KEY("Id") +); +INSERT INTO SHS VALUES(1,' SHS 25 x 25 x 2.6',25.0,25.0,2.6,1.69,2.16,1.72,1.72,0.89,0.89,1.38,1.38,1.76,1.76,'IS 4923:1997'); +INSERT INTO SHS VALUES(2,' SHS 25 x 25 x 3.2',25.0,25.0,3.2,1.98,2.53,1.89,1.89,0.86,0.86,1.51,1.51,1.98,1.98,'IS 4923:1997'); +INSERT INTO SHS VALUES(3,' SHS 30 x 30 x 2.6',30.0,30.0,2.6,2.1,2.68,3.23,3.23,1.1,1.1,2.15,2.15,2.68,2.68,'IS 4923:1997'); +INSERT INTO SHS VALUES(4,' SHS 30 x 30 x 3.2',30.0,30.0,3.2,2.49,3.17,3.62,3.62,1.07,1.07,2.41,2.41,3.08,3.08,'IS 4923:1997'); +INSERT INTO SHS VALUES(5,' SHS 30 x 30 x 4.0',30.0,30.0,4.0,2.94,3.75,3.97,3.97,1.03,1.03,2.64,2.64,3.5,3.5,'IS 4923:1997'); +INSERT INTO SHS VALUES(6,' SHS 32 x 32 x 2.6',32.0,32.0,2.6,2.26,2.88,4.02,4.02,1.18,1.18,2.51,2.51,3.11,3.11,'IS 4923:1997'); +INSERT INTO SHS VALUES(7,' SHS 32 x 32 x 3.2',32.0,32.0,3.2,2.69,3.42,4.54,4.54,1.15,1.15,2.84,2.84,3.59,3.59,'IS 4923:1997'); +INSERT INTO SHS VALUES(8,' SHS 32 x 32 x 4.0',32.0,32.0,4.0,3.19,4.07,5.02,5.02,1.11,1.11,3.14,3.14,4.11,4.11,'IS 4923:1997'); +INSERT INTO SHS VALUES(9,' SHS 35 x 35 x 2.6',35.0,35.0,2.6,2.51,3.2,5.43,5.43,1.3,1.3,3.1,3.1,3.81,3.81,'IS 4923:1997'); +INSERT INTO SHS VALUES(10,' SHS 35 x 35 x 3.2',35.0,35.0,3.2,2.99,3.81,6.18,6.18,1.27,1.27,3.53,3.53,4.42,4.42,'IS 4923:1997'); +INSERT INTO SHS VALUES(11,' SHS 35 x 35 x 4.0',35.0,35.0,4.0,3.57,4.55,6.93,6.93,1.23,1.23,3.96,3.96,5.11,5.11,'IS 4923:1997'); +INSERT INTO SHS VALUES(12,' SHS 38 x 38 x 2.6',38.0,38.0,2.6,2.75,3.51,7.14,7.14,1.43,1.43,3.76,3.76,4.57,4.57,'IS 4923:1997'); +INSERT INTO SHS VALUES(13,' SHS 38 x 38 x 2.9',38.0,38.0,2.9,3.03,3.86,7.68,7.68,1.41,1.41,4.04,4.04,4.97,4.97,'IS 4923:1997'); +INSERT INTO SHS VALUES(14,' SHS 38 x 38 x 3.2',38.0,38.0,3.2,3.29,4.19,8.18,8.18,2.4,2.4,4.3,4.3,5.34,5.34,'IS 4923:1997'); +INSERT INTO SHS VALUES(15,' SHS 38 x 38 x 3.6',38.0,38.0,3.6,3.63,4.62,8.76,8.76,1.38,1.38,4.61,4.61,5.8,5.8,'IS 4923:1997'); +INSERT INTO SHS VALUES(16,' SHS 38 x 38 x 4.0',38.0,38.0,4.0,3.95,5.03,9.26,9.26,1.36,1.36,4.87,4.87,6.22,6.22,'IS 4923:1997'); +INSERT INTO SHS VALUES(17,' SHS 40 x 40 x 2.6',40.0,40.0,2.6,2.92,3.72,8.45,8.45,1.51,1.51,4.22,4.22,5.12,5.12,'IS 4923:1997'); +INSERT INTO SHS VALUES(18,' SHS 40 x 40 x 3.2',40.0,40.0,3.2,3.49,4.45,9.72,9.72,1.48,1.48,4.86,4.86,6.01,6.01,'IS 4923:1997'); +INSERT INTO SHS VALUES(19,' SHS 40 x 40 x 3.6',40.0,40.0,3.6,3.85,4.91,10.45,10.45,1.46,1.46,5.22,5.22,6.53,6.53,'IS 4923:1997'); +INSERT INTO SHS VALUES(20,' SHS 40 x 40 x 4.0',40.0,40.0,4.0,4.2,5.35,11.07,11.07,1.44,1.44,5.54,5.54,7.01,7.01,'IS 4923:1997'); +INSERT INTO SHS VALUES(21,' SHS 45 x 45 x 2.6',45.0,45.0,2.6,3.32,4.24,12.47,12.47,1.71,1.71,5.52,5.52,6.64,6.64,'IS 4923:1997'); +INSERT INTO SHS VALUES(22,' SHS 45 x 45 x 2.9',45.0,45.0,2.9,3.66,4.67,13.45,13.45,1.7,1.7,5.98,5.98,7.25,7.25,'IS 4923:1997'); +INSERT INTO SHS VALUES(23,' SHS 45 x 45 x 3.2',45.0,45.0,3.2,3.99,5.09,14.41,14.41,1.68,1.68,6.4,6.4,7.83,7.83,'IS 4923:1997'); +INSERT INTO SHS VALUES(24,' SHS 45 x 45 x 3.6',45.0,45.0,3.6,4.42,5.63,15.57,15.57,1.66,1.66,6.92,6.92,8.55,8.55,'IS 4923:1997'); +INSERT INTO SHS VALUES(25,' SHS 45 x 45 x 4.5',45.0,45.0,4.5,5.31,6.77,17.74,17.74,1.62,1.62,7.88,7.88,9.99,9.99,'IS 4923:1997'); +INSERT INTO SHS VALUES(26,' SHS 49.5 x 49.5 x 2.9',49.0,49.0,2.9,4.07,5.19,18.37,18.37,1.88,1.88,7.42,7.42,8.93,8.93,'IS 4923:1997'); +INSERT INTO SHS VALUES(27,' SHS 49.5 x 49.5 x 3.6',49.0,49.0,3.6,4.93,6.28,21.42,21.42,1.85,1.85,8.66,8.66,10.6,10.6,'IS 4923:1997'); +INSERT INTO SHS VALUES(28,' SHS 49.5 x 49.5 x 4.5',49.0,49.0,4.5,5.95,7.58,24.64,24.64,1.8,1.8,9.96,9.96,12.47,12.47,'IS 4923:1997'); +INSERT INTO SHS VALUES(29,' SHS 63.5 x 63.5 x 3.2',63.0,63.0,3.2,5.85,7.45,44.35,44.35,2.44,2.44,13.97,13.97,16.65,16.65,'IS 4923:1997'); +INSERT INTO SHS VALUES(30,' SHS 63.5 x 63.5 x 3.6',63.0,63.0,3.6,6.51,8.29,48.55,48.55,2.42,2.42,15.29,15.29,18.36,18.36,'IS 4923:1997'); +INSERT INTO SHS VALUES(31,' SHS 63.5 x 63.5 x 4.5',63.0,63.0,4.5,7.93,10.1,57.0,57.0,2.38,2.38,17.95,17.95,21.93,21.93,'IS 4923:1997'); +INSERT INTO SHS VALUES(32,' SHS 72 x 72 x 3.2',72.0,72.0,3.2,6.71,8.54,66.32,66.32,2.79,2.79,18.42,18.42,21.8,21.8,'IS 4923:1997'); +INSERT INTO SHS VALUES(33,' SHS 72 x 72 x 4.0',72.0,72.0,4.0,8.22,10.47,79.03,79.03,2.75,2.75,21.95,21.95,26.32,26.32,'IS 4923:1997'); +INSERT INTO SHS VALUES(34,' SHS 72 x 72 x 4.8',72.0,72.0,4.8,9.66,12.31,90.31,90.31,2.71,2.71,25.09,25.09,30.49,30.49,'IS 4923:1997'); +INSERT INTO SHS VALUES(35,' SHS 75 x 75 x 3.2',75.0,75.0,3.2,7.01,8.93,75.53,75.53,2.91,2.91,20.41,20.41,23.79,23.79,'IS 4923:1997'); +INSERT INTO SHS VALUES(36,' SHS 75 x 75 x 4.0',75.0,75.0,4.0,8.59,10.95,90.19,90.19,2.87,2.87,24.05,24.05,28.76,28.76,'IS 4923:1997'); +INSERT INTO SHS VALUES(37,' SHS 75 x 75 x 4.9',75.0,75.0,4.9,10.3,13.12,104.82,104.82,2.83,2.83,27.95,27.95,33.92,33.92,'IS 4923:1997'); +INSERT INTO SHS VALUES(38,' SHS 88.9 x 88.9 x 3.6',88.0,88.0,3.6,9.38,11.95,142.83,142.83,3.46,3.46,32.13,32.13,37.85,37.85,'IS 4923:1997'); +INSERT INTO SHS VALUES(39,' SHS 88.9 x 88.9 x 4.5',88.0,88.0,4.5,11.52,14.67,170.97,170.97,3.41,3.41,38.46,38.46,45.55,45.55,'IS 4923:1997'); +INSERT INTO SHS VALUES(40,' SHS 88.9 x 88.9 x 4.9',88.0,88.0,4.9,12.44,15.85,182.57,182.57,3.39,3.39,41.07,41.07,49.23,49.23,'IS 4923:1997'); +INSERT INTO SHS VALUES(41,' SHS 91.5 x 91.5 x 3.6',91.0,91.0,3.6,9.67,12.32,156.49,156.49,3.56,3.56,34.21,34.21,40.24,40.24,'IS 4923:1997'); +INSERT INTO SHS VALUES(42,' SHS 91.5 x 91.5 x 4.5',91.0,91.0,4.5,11.88,15.14,187.57,187.57,3.52,3.52,41.0,41.0,48.79,48.79,'IS 4923:1997'); +INSERT INTO SHS VALUES(43,' SHS 91.5 x 91.5 x 5.4',91.0,91.0,5.4,14.01,17.85,215.68,215.68,3.48,3.48,47.14,47.14,56.77,56.77,'IS 4923:1997'); +INSERT INTO SHS VALUES(44,' SHS 100 x 100 x 4.0',100.0,100.0,4.0,11.73,14.95,226.35,226.35,3.89,3.89,45.27,45.27,53.3,53.3,'IS 4923:1997'); +INSERT INTO SHS VALUES(45,' SHS 100 x 100 x 5.0',100.0,100.0,5.0,14.41,18.36,271.1,271.1,3.84,3.84,54.22,54.22,64.59,64.59,'IS 4923:1997'); +INSERT INTO SHS VALUES(46,' SHS 100 x 100 x 6.0',100.0,100.0,6.0,16.98,21.63,311.47,311.47,3.79,3.79,62.29,62.29,75.1,75.1,'IS 4923:1997'); +INSERT INTO SHS VALUES(47,' SHS 113.5 x 113.5 x 4.5',113.0,113.0,4.5,14.99,19.1,372.88,372.88,4.42,4.42,65.71,65.71,77.33,77.33,'IS 4923:1997'); +INSERT INTO SHS VALUES(48,' SHS 113.5 x 113.5 x 4.8',113.0,113.0,4.8,15.92,20.28,393.31,393.31,4.4,4.4,69.3,69.3,81.81,81.81,'IS 4923:1997'); +INSERT INTO SHS VALUES(49,' SHS 113.5 x 113.5 x 5.4',113.0,113.0,5.4,17.74,22.6,432.58,432.58,4.38,4.38,76.23,76.23,90.55,90.55,'IS 4923:1997'); +INSERT INTO SHS VALUES(50,' SHS 113.5 x I13.5 x 6.0',113.0,113.0,6.0,19.53,24.87,469.81,469.81,4.35,4.35,82.79,82.79,98.96,98.96,'IS 4923:1997'); +INSERT INTO SHS VALUES(51,' SHS 125 x 125 x 4.5',125.0,125.0,4.5,16.62,21.17,505.83,505.83,4.89,4.89,80.93,80.93,94.54,94.54,'IS 4923:1997'); +INSERT INTO SHS VALUES(52,' SHS 125 x 125 x 5.0',125.0,125.0,5.0,18.33,23.36,552.62,552.62,4.86,4.86,88.42,88.42,104.1,104.1,'IS 4923:1997'); +INSERT INTO SHS VALUES(53,' SHS 125 x 125 x 6.0',125.0,125.0,6.0,21.69,27.63,640.89,640.89,4.82,4.82,102.54,102.54,121.87,121.87,'IS 4923:1997'); +INSERT INTO SHS VALUES(54,' SHS 132 x 132 x 4.8',132.0,132.0,4.8,18.71,23.83,634.39,634.39,5.16,5.16,96.12,96.12,112.69,112.69,'IS 4923:1997'); +INSERT INTO SHS VALUES(55,' SHS 132 x 132 x 5.4',132.0,132.0,5.4,20.88,26.59,700.11,700.11,5.13,5.13,106.08,106.08,125.02,125.02,'IS 4923:1997'); +INSERT INTO SHS VALUES(56,' SHS 132 x 132 x 6.0',132.0,132.0,6.0,23.01,29.31,762.98,762.98,5.1,5.1,115.6,115.6,136.98,136.98,'IS 4923:1997'); +INSERT INTO SHS VALUES(57,' SHS 150 x 150 x 5.0',150.0,150.0,5.0,22.26,28.36,982.12,982.12,5.89,5.89,130.95,130.95,152.98,152.98,'IS 4923:1997'); +INSERT INTO SHS VALUES(58,' SHS 150 x 150 x 6.0',150.0,150.0,6.0,26.4,33.63,1145.91,1145.91,5.84,5.84,152.79,152.79,179.88,179.88,'IS 4923:1997'); +INSERT INTO SHS VALUES(59,' SHS 180 x 180 x 4.0',180.0,180.0,4.0,21.9,27.9,1434.0,1434.0,7.17,7.17,159.0,159.0,184.0,184.0,'IS 4923:1997'); +INSERT INTO SHS VALUES(60,' SHS 180 x 180 x 5.0',180.0,180.0,5.0,27.2,34.6,1755.0,1755.0,7.12,7.12,195.0,195.0,226.0,226.0,'IS 4923:1997'); +INSERT INTO SHS VALUES(61,' SHS 180 x 180 x 6.0',180.0,180.0,6.0,32.05,40.83,2036.0,2036.0,7.06,7.06,226.0,226.0,280.0,280.0,'IS 4923:1997'); +INSERT INTO SHS VALUES(62,' SHS 180 x 180 x 8.0',180.0,180.0,8.0,41.91,53.39,2590.73,2590.73,6.97,6.97,287.86,287.86,340.68,340.68,'IS 4923:1997'); +CREATE TABLE IF NOT EXISTS "RHS" ( + "Id" INTEGER NOT NULL, + "Designation" VARCHAR, + "D" REAL(10 , 2), + "B" REAL(10 , 2), + "T" REAL(10 , 2), + "W" REAL(10 , 2), + "A" REAL(10 , 2), + "Izz" REAL(10 , 2), + "Iyy" REAL(10 , 2), + "Rzz" REAL(10 , 2), + "Ryy" REAL(10 , 2), + "Zzz" REAL(10 , 2), + "Zyy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "Source" VARCHAR(50), + PRIMARY KEY("Id") +); +INSERT INTO RHS VALUES(1,' RHS 50 x 25 x 2.9',50.0,25.0,2.9,2.98,3.8,10.93,3.6,1.7,0.97,4.37,2.88,5.72,3.48,'IS 4923:1997'); +INSERT INTO RHS VALUES(2,' RHS 50 x 25 x 3.2',50.0,25.0,3.2,3.24,4.13,11.63,3.8,1.68,0.96,4.65,3.04,6.14,3.73,'IS 4923:1997'); +INSERT INTO RHS VALUES(3,' RHS 60 x 40 x 2.9',60.0,40.0,2.9,4.12,5.25,24.74,13.11,2.17,1.58,8.25,6.56,10.25,7.73,'IS 4923:1997'); +INSERT INTO RHS VALUES(4,' RHS 66 x 33 x 2.9',66.0,33.0,2.9,4.07,5.19,27.33,9.12,2.29,1.33,8.28,5.53,10.59,6.49,'IS 4923:1997'); +INSERT INTO RHS VALUES(5,' RHS 66 x 33 x 3.6',66.0,33.0,3.6,4.93,6.28,31.87,10.52,2.25,1.29,9.66,6.37,12.56,7.66,'IS 4923:1997'); +INSERT INTO RHS VALUES(6,' RHS 66 x 33 x 4.5',66.0,33.0,4.5,5.95,7.58,36.64,11.93,2.2,1.25,11.1,7.23,14.77,8.94,'IS 4923:1997'); +INSERT INTO RHS VALUES(7,' RHS 70 x 30 x 2.9',70.0,30.0,2.9,4.12,5.25,29.82,7.72,2.38,1.21,8.52,5.14,11.07,6.04,'IS 4923:1997'); +INSERT INTO RHS VALUES(8,' RHS 70 x 30 x 3.2',70.0,30.0,3.2,4.5,5.73,32.04,8.24,2.37,1.2,9.15,5.49,11.98,6.51,'IS 4923:1997'); +INSERT INTO RHS VALUES(9,' RHS 70 x 30 x 4.0',70.0,30.0,4.0,5.45,6.95,37.23,9.42,2.31,1.16,10.64,6.28,14.2,7.66,'IS 4923:1997'); +INSERT INTO RHS VALUES(10,' RHS 80 x 40 x 2.9',80.0,40.0,2.9,5.03,6.41,50.87,17.11,2.82,1.63,12.72,8.56,16.07,9.88,'IS 4923:1997'); +INSERT INTO RHS VALUES(11,' RHS 80 x 40 x 3.2',80.0,40.0,3.2,5.5,7.01,54.94,18.41,2.8,1.62,13.74,9.21,17.46,10.72,'IS 4923:1997'); +INSERT INTO RHS VALUES(12,' RHS 80 x 40 x 4.0',80.0,40.0,4.0,6.71,8.55,64.79,21.49,2.75,1.59,16.2,10.74,20.91,12.77,'IS 4923:1997'); +INSERT INTO RHS VALUES(13,' RHS 96 x 48 x 3.2',96.0,48.0,3.2,6.71,8.54,98.61,33.28,3.4,1.97,20.54,13.87,25.85,15.91,'IS 4923:1997'); +INSERT INTO RHS VALUES(14,' RHS 96 x 48 x 4.0',96.0,48.0,4.0,8.22,10.47,117.54,39.32,3.55,1.94,24.49,16.3,31.21,19.14,'IS 4923:1997'); +INSERT INTO RHS VALUES(15,' RHS 96 x 48 x 4.8',96.0,48.0,4.8,9.66,12.31,134.35,44.55,3.3,1.9,27.99,18.56,36.13,22.08,'IS 4923:1997'); +INSERT INTO RHS VALUES(16,' RHS 100 x 50 x 3.2',100.0,50.0,3.2,7.01,8.93,112.29,37.95,3.55,2.06,22.46,15.18,28.2,17.37,'IS 4923:1997'); +INSERT INTO RHS VALUES(17,' RHS 100 x 50 x 4.0',100.0,50.0,4.0,8.59,10.95,134.14,44.95,3.5,2.03,26.83,17.98,34.1,20.93,'IS 4923:1997'); +INSERT INTO RHS VALUES(18,' RHS 122 x 61 x 3.6',122.0,61.0,3.6,9.67,12.32,232.61,78.83,4.34,2.35,38.13,25.84,47.71,29.42,'IS 4923:1997'); +INSERT INTO RHS VALUES(19,' RHS 122 x 61 x 4.5',122.0,61.0,4.5,11.88,15.14,278.94,93.78,4.29,2.49,45.73,30.75,57.85,35.56,'IS 4923:1997'); +INSERT INTO RHS VALUES(20,' RHS 122 x 61 x 5.4',122.0,61.0,5.4,14.01,17.85,320.83,107.03,4.24,2.45,52.6,35.09,67.29,41.22,'IS 4923:1997'); +INSERT INTO RHS VALUES(21,' RHS 127 x 50 x 3.6',127.0,50.0,3.6,9.34,11.89,227.08,52.05,4.37,2.09,35.76,20.82,45.95,23.7,'IS 4923:1997'); +INSERT INTO RHS VALUES(22,' RHS 127 x 50 x 4.6',127.0,50.0,4.6,11.69,14.89,276.33,62.46,4.31,2.05,43.52,24.98,56.66,29.04,'IS 4923:1997'); +INSERT INTO RHS VALUES(23,' RHS 145 x 82 x 4.8',145.0,82.0,4.8,15.92,20.28,555.16,228.5,5.23,3.36,76.57,55.73,94.93,63.93,'IS 4923:1997'); +INSERT INTO RHS VALUES(24,' RHS 145 x 82 x 5.4',145.0,82.0,5.4,17.74,22.6,610.85,250.59,5.2,3.33,84.26,61.12,105.07,70.66,'IS 4923:1997'); +INSERT INTO RHS VALUES(25,' RHS 172 x 92 x 4.8',172.0,92.0,4.8,18.71,23.83,917.13,346.91,6.2,3.82,106.64,75.41,132.08,85.61,'IS 4923:1997'); +INSERT INTO RHS VALUES(26,' RHS 172 x 92 x 5.4',172.0,92.0,5.4,20.88,26.59,1012.47,381.74,6.17,3.79,117.73,82.99,146.55,94.86,'IS 4923:1997'); +CREATE TABLE IF NOT EXISTS "CHS" ( + "Id" INTEGER, + "Designation" VARCHAR, + "NB" VARCHAR, + "OD" REAL(10 , 2), + "T" REAL(10 , 2), + "W" REAL(10 , 2), + "A" REAL(10 , 2), + "V" REAL(10 , 2), + "Ves" REAL(10 , 2), + "Vis" REAL(10 , 2), + "I" REAL(10 , 2), + "Z" REAL(10 , 2), + "R" REAL(10 , 2), + "Rsq" REAL(10 , 2), + "Source" VARCHAR, + PRIMARY KEY("Id") +); +INSERT INTO CHS VALUES(1,' CHS 21.3 x 2','15',21.3,2.0,0.95,1.21,235.0,669.0,543.0,0.57,0.54,0.69,0.47,'IS 1161:2014'); +INSERT INTO CHS VALUES(2,' CHS 21.3 x 2.6','15',21.3,2.6,1.2,1.53,204.0,669.0,506.0,0.68,0.64,0.67,0.45,'IS 1161:2014'); +INSERT INTO CHS VALUES(3,' CHS 21.3 x 3.2','15',21.3,3.2,1.43,1.82,174.0,669.0,468.0,0.77,0.72,0.65,0.42,'IS 1161:2014'); +INSERT INTO CHS VALUES(4,' CHS 26.9 x 2.3','20',26.9,2.3,1.4,1.78,391.0,845.0,701.0,1.36,1.01,0.87,0.76,'IS 1161:2014'); +INSERT INTO CHS VALUES(5,' CHS 26.9 x 2.6','20',26.9,2.6,1.56,1.98,370.0,845.0,682.0,1.48,1.1,0.86,0.75,'IS 1161:2014'); +INSERT INTO CHS VALUES(6,' CHS 26.9 x 3.2','20',26.9,3.2,1.87,2.38,330.0,845.0,644.0,1.7,1.27,0.85,0.71,'IS 1161:2014'); +INSERT INTO CHS VALUES(7,' CHS 33.7 x 2.6','25',33.7,2.6,1.99,2.54,638.0,1059.0,895.0,3.09,1.84,1.1,1.22,'IS 1161:2014'); +INSERT INTO CHS VALUES(8,' CHS 33.7 x 3.2','25',33.7,3.2,2.41,3.07,585.0,1059.0,858.0,3.6,2.14,1.08,1.18,'IS 1161:2014'); +INSERT INTO CHS VALUES(9,' CHS 33.7 x 4','25',33.7,4.0,2.93,3.73,519.0,1059.0,807.0,4.19,2.49,1.06,1.12,'IS 1161:2014'); +INSERT INTO CHS VALUES(10,' CHS 42.4 x 2.6','32',42.4,2.6,2.55,3.25,1087.0,1332.0,1169.0,6.46,3.05,1.41,1.99,'IS 1161:2014'); +INSERT INTO CHS VALUES(11,' CHS 42.4 x 3.2','32',42.4,3.2,3.09,3.94,1018.0,1332.0,1131.0,7.62,3.59,1.39,1.93,'IS 1161:2014'); +INSERT INTO CHS VALUES(12,' CHS 42.4 x 4','32',42.4,4.0,3.79,4.83,929.0,1332.0,1081.0,8.99,4.24,1.36,1.86,'IS 1161:2014'); +INSERT INTO CHS VALUES(13,' CHS 48.3 x 2.9','40',48.3,2.9,3.25,4.14,1419.0,1517.0,1335.0,10.7,4.43,1.61,2.59,'IS 1161:2014'); +INSERT INTO CHS VALUES(14,' CHS 48.3 x 3.2','40',48.3,3.2,3.56,4.53,1379.0,1517.0,1316.0,11.59,4.8,1.6,2.56,'IS 1161:2014'); +INSERT INTO CHS VALUES(15,' CHS 48.3 x 4','40',48.3,4.0,4.37,5.57,1276.0,1517.0,1266.0,13.77,5.7,1.57,2.47,'IS 1161:2014'); +INSERT INTO CHS VALUES(16,' CHS 60.3 x 2.9','50',60.3,2.9,4.11,5.23,2333.0,1894.0,1712.0,21.59,7.15,2.03,4.13,'IS 1161:2014'); +INSERT INTO CHS VALUES(17,' CHS 60.3 x 3.6','50',60.3,3.6,5.03,6.41,2215.0,1894.0,1668.0,25.87,8.58,2.01,4.03,'IS 1161:2014'); +INSERT INTO CHS VALUES(18,' CHS 60.3 x 4.5','50',60.3,4.5,6.19,7.89,2067.0,1894.0,1612.0,30.9,10.25,1.98,3.92,'IS 1161:2014'); +INSERT INTO CHS VALUES(19,' CHS 76.1 x 2.9','65',76.1,2.9,5.24,0.67,3882.0,2391.0,2209.0,44.74,11.76,2.59,6.71,'IS 1161:2014'); +INSERT INTO CHS VALUES(20,' CHS 76.1 x 3.6','65',76.1,3.6,6.44,8.2,3728.0,2391.0,2165.0,54.01,14.19,2.57,6.59,'IS 1161:2014'); +INSERT INTO CHS VALUES(21,' CHS 76.1 x 4.5','65',76.1,4.5,7.95,10.12,3536.0,2391.0,2108.0,65.12,17.11,2.54,6.43,'IS 1161:2014'); +INSERT INTO CHS VALUES(22,' CHS 88.9 x 3.2','80',88.9,3.2,6.76,8.62,5346.0,2793.0,2592.0,79.21,17.82,3.03,9.19,'IS 1161:2014'); +INSERT INTO CHS VALUES(23,' CHS 88.9 x 4','80',88.9,4.0,8.38,10.67,5140.0,2793.0,2542.0,95.34,21.67,3.0,9.03,'IS 1161:2014'); +INSERT INTO CHS VALUES(24,' CHS 88.9 x 4.8','80',88.9,4.8,9.96,12.68,4939.0,2793.0,2491.0,112.49,25.31,2.98,8.87,'IS 1161:2014'); +INSERT INTO CHS VALUES(25,' CHS 101.6 x 3.6','90',101.6,3.6,8.7,11.08,6999.0,3192.0,2966.0,133.24,26.23,3.47,12.02,'IS 1161:2014'); +INSERT INTO CHS VALUES(26,' CHS 101.6 x 4','90',101.6,4.0,9.63,12.26,6881.0,3192.0,2941.0,146.28,18.8,3.45,11.93,'IS 1161:2014'); +INSERT INTO CHS VALUES(27,' CHS 101.6 x 4.8','90',101.6,4.8,11.46,14.6,6648.0,3192.0,2890.0,171.39,33.74,3.43,11.74,'IS 1161:2014'); +INSERT INTO CHS VALUES(28,' CHS 114.3 x 3.6','100',114.3,3.6,9.83,12.52,9009.0,3591.0,3365.0,191.98,33.59,3.92,15.33,'IS 1161:2014'); +INSERT INTO CHS VALUES(29,' CHS 114.3 x 4.5','100',114.3,4.5,12.19,15.52,8709.0,3591.0,3308.0,234.32,41.0,3.89,15.1,'IS 1161:2014'); +INSERT INTO CHS VALUES(30,' CHS 114.3 x 5.4','100',114.3,5.4,14.5,18.47,8413.0,3591.0,3252.0,274.54,48.04,3.85,14.86,'IS 1161:2014'); +INSERT INTO CHS VALUES(31,' CHS 127 x 4.5','110',127.0,4.5,13.59,17.32,10936.0,3990.0,3707.0,325.29,51.23,4.33,18.78,'IS 1161:2014'); +INSERT INTO CHS VALUES(32,' CHS 127 x 4.8','110',127.0,4.8,14.47,18.43,10825.0,3990.0,3688.0,344.5,54.25,4.32,18.69,'IS 1161:2014'); +INSERT INTO CHS VALUES(33,' CHS 127 x 5.4','110',127.0,5.4,16.19,20.63,10605.0,3990.0,3651.0,382.04,60.16,4.3,18.52,'IS 1161:2014'); +INSERT INTO CHS VALUES(34,' CHS 139.7 x 4.5','125',139.7,4.5,15.0,19.11,13417.0,4389.0,4106.0,437.2,62.59,4.78,22.87,'IS 1161:2014'); +INSERT INTO CHS VALUES(35,' CHS 139.7 x 4.8','125',139.7,4.8,15.97,20.34,13295.0,4389.0,4087.0,463.33,66.33,4.77,22.78,'IS 1161:2014'); +INSERT INTO CHS VALUES(36,' CHS 139.7 x 5.4','125',139.7,5.4,17.89,22.78,13050.0,4389.0,4050.0,514.5,73.66,4.75,22.58,'IS 1161:2014'); +INSERT INTO CHS VALUES(37,' CHS 152.4 x 4.5','135',152.4,4.5,16.41,20.91,16151.0,4788.0,4505.0,572.24,75.1,5.23,27.37,'IS 1161:2014'); +INSERT INTO CHS VALUES(38,' CHS 152.4 x 4.8','135',152.4,4.8,17.47,22.26,16016.0,4788.0,4486.0,606.76,79.63,5.22,27.26,'IS 1161:2014'); +INSERT INTO CHS VALUES(39,' CHS 152.4 x 5.4','135',152.4,5.4,19.58,24.94,15748.0,4788.0,4448.0,674.51,88.52,5.2,27.05,'IS 1161:2014'); +INSERT INTO CHS VALUES(40,' CHS 165.1 x 4.5','150',165.1,4.5,17.82,22.7,19138.0,5187.0,4904.0,732.57,88.74,5.68,32.27,'IS 1161:2014'); +INSERT INTO CHS VALUES(41,' CHS 165.1 x 4.8','150',165.1,4.8,18.98,24.17,18991.0,5187.0,4885.0,777.13,94.14,5.67,32.15,'IS 1161:2014'); +INSERT INTO CHS VALUES(42,' CHS 165.1 x 5.4','150',165.1,5.4,21.27,27.09,18699.0,5187.0,4847.0,864.7,104.75,5.65,31.92,'IS 1161:2014'); +INSERT INTO CHS VALUES(43,' CHS 165.1 x 5.9','150',165.1,5.9,23.2,29.5,18465.0,5189.0,4818.0,970.0,113.4,5.63,31.72,'IS 1161:2014'); +INSERT INTO CHS VALUES(44,' CHS 165.1 x 6.3','150',165.1,6.3,24.67,31.43,18265.0,5187.0,4791.0,992.28,120.2,5.62,31.57,'IS 1161:2014'); +INSERT INTO CHS VALUES(45,' CHS 165.1 x 8','150',165.1,8.0,30.99,39.48,17460.0,5187.0,4684.0,1221.25,147.94,5.56,30.93,'IS 1161:2014'); +INSERT INTO CHS VALUES(46,' CHS 168.3 x 4.5','150',168.3,4.5,18.18,23.16,19931.0,5287.0,5005.0,777.22,92.36,5.79,33.56,'IS 1161:2014'); +INSERT INTO CHS VALUES(47,' CHS 168.3 x 4.8','150',168.3,4.8,19.35,24.66,19781.0,5287.0,4986.0,824.57,97.99,5.78,33.44,'IS 1161:2014'); +INSERT INTO CHS VALUES(48,' CHS 168.3 x 5.4','150',168.3,5.4,21.69,27.64,19483.0,5287.0,4948.0,917.69,109.05,5.76,33.21,'IS 1161:2014'); +INSERT INTO CHS VALUES(49,' CHS 168.3 x 6.3','150',168.3,6.3,25.17,32.06,19040.0,5287.0,4891.0,1053.42,125.18,5.73,32.85,'IS 1161:2014'); +INSERT INTO CHS VALUES(50,' CHS 168.3 x 8','150',168.3,8.0,31.63,40.29,18218.0,5287.0,4785.0,1297.27,154.16,5.67,32.2,'IS 1161:2014'); +INSERT INTO CHS VALUES(51,' CHS 168.3 x 10','150',168.3,10.0,39.04,49.73,17273.0,5287.0,4659.0,1563.98,185.86,5.61,31.45,'IS 1161:2014'); +INSERT INTO CHS VALUES(52,' CHS 193.7 x 4.8','175',193.7,4.8,22.36,28.49,26619.0,6085.0,5784.0,1271.39,131.27,6.68,44.63,'IS 1161:2014'); +INSERT INTO CHS VALUES(53,' CHS 193.7 x 5.4','175',193.7,5.4,25.08,31.94,26273.0,6085.0,5746.0,1416.97,146.31,6.66,44.36,'IS 1161:2014'); +INSERT INTO CHS VALUES(54,' CHS 193.7 x 5.9','175',193.7,5.9,27.33,34.81,25987.0,6085.0,5715.0,1536.13,158.61,6.64,44.13,'IS 1161:2014'); +INSERT INTO CHS VALUES(55,' CHS 193.7 x 6.3','175',193.7,6.3,29.12,37.09,25759.0,6085.0,5689.0,1630.05,168.31,6.63,43.95,'IS 1161:2014'); +INSERT INTO CHS VALUES(56,' CHS 193.7 x 8','175',193.7,8.0,36.64,46.67,24801.0,6085.0,5583.0,2015.54,208.11,6.57,43.19,'IS 1161:2014'); +INSERT INTO CHS VALUES(57,' CHS 193.7 x 10','175',193.7,10.0,45.3,57.71,23697.0,6085.0,5457.0,2441.59,252.1,6.5,42.31,'IS 1161:2014'); +INSERT INTO CHS VALUES(58,' CHS 193.7 x 12','175',193.7,12.0,53.77,68.5,22618.0,6085.0,5331.0,2839.2,293.15,6.44,41.45,'IS 1161:2014'); +INSERT INTO CHS VALUES(59,' CHS 219.1 x 4.8','200',219.1,4.8,25.37,32.32,34471.0,6883.0,6582.0,1856.03,169.42,7.58,57.43,'IS 1161:2014'); +INSERT INTO CHS VALUES(60,' CHS 219.1 x 5.6','200',219.1,5.6,29.49,37.56,33947.0,6883.0,6531.0,2141.61,195.49,7.55,57.02,'IS 1161:2014'); +INSERT INTO CHS VALUES(61,' CHS 219.1 x 5.9','200',219.1,5.9,31.02,39.52,33751.0,6883.0,6513.0,2247.01,205.11,7.54,56.86,'IS 1161:2014'); +INSERT INTO CHS VALUES(62,' CHS 219.1 x 6.3','200',219.1,6.3,33.06,42.12,33491.0,6883.0,6487.0,2386.14,217.81,7.53,56.65,'IS 1161:2014'); +INSERT INTO CHS VALUES(63,' CHS 219.1 x 8','200',219.1,8.0,41.65,53.06,32397.0,6883.0,6381.0,2959.63,'270.I6',7.47,55.78,'IS 1161:2014'); +INSERT INTO CHS VALUES(64,' CHS 219.1 x 10','200',219.1,10.0,51.57,65.69,31134.0,6883.0,6255.0,3598.44,328.47,7.4,54.78,'IS 1161:2014'); +INSERT INTO CHS VALUES(65,' CHS 219.1 x 12','200',219.1,12.0,61.29,78.07,29895.0,6883.0,6129.0,4199.88,383.38,7.33,53.79,'IS 1161:2014'); +INSERT INTO CHS VALUES(66,' CHS 244.5 x 5.9','225',244.5,5.9,34.72,44.23,42529.0,7681.0,7310.0,3149.12,257.6,8.44,71.21,'IS 1161:2014'); +INSERT INTO CHS VALUES(67,' CHS 244.5 x 6.3','225',244.5,6.3,37.01,47.14,42237.0,7681.0,7285.0,3346.03,273.7,8.42,70.97,'IS 1161:2014'); +INSERT INTO CHS VALUES(68,' CHS 244.5 x 8','225',244.5,8.0,46.66,59.44,41007.0,7681.0,7179.0,4160.45,340.32,8.37,70.0,'IS 1161:2014'); +INSERT INTO CHS VALUES(69,' CHS 244.5 x 10','225',244.5,10.0,57.83,73.67,39584.0,7681.0,7053.0,5073.15,414.98,8.3,68.86,'IS 1161:2014'); +INSERT INTO CHS VALUES(70,' CHS 273 x 5.9','250',273.0,5.9,38.86,49.51,53584.0,8577.0,8206.0,4417.18,323.6,9.45,89.22,'IS 1161:2014'); +INSERT INTO CHS VALUES(71,' CHS 273 x 6.3','250',273.0,6.3,41.44,52.79,53256.0,8577.0,8181.0,4695.82,344.02,9.43,88.96,'IS 1161:2014'); +INSERT INTO CHS VALUES(72,' CHS 273 x 8','250',273.0,8.0,52.28,66.6,51875.0,8577.0,8074.0,5851.71,428.7,9.37,87.86,'IS 1161:2014'); +INSERT INTO CHS VALUES(73,' CHS 273 x 10','250',273.0,10.0,64.86,82.62,50273.0,8577.0,7948.0,7154.09,524.11,9.31,86.59,'IS 1161:2014'); +INSERT INTO CHS VALUES(74,' CHS 273 x 12','250',273.0,12.0,77.24,98.39,48695.0,8577.0,7823.0,8396.14,615.1,9.24,85.33,'IS 1161:2014'); +INSERT INTO CHS VALUES(75,' CHS 323.9 x 6.3','300',323.9,6.3,49.34,62.86,76111.0,10176.0,9780.0,7928.9,489.59,11.23,126.14,'IS 1161:2014'); +INSERT INTO CHS VALUES(76,' CHS 323.9 x 8','300',323.9,8.0,62.32,79.39,74458.0,10176.0,9673.0,9910.08,611.92,11.17,124.82,'IS 1161:2014'); +INSERT INTO CHS VALUES(77,' CHS 323.9 x 10','300',323.9,10.0,77.41,98.61,72536.0,10176.0,9547.0,12158.34,750.75,11.1,123.29,'IS 1161:2014'); +INSERT INTO CHS VALUES(78,' CHS 323.9 x 12','300',323.9,12.0,92.3,117.58,70639.0,10176.0,9422.0,14319.56,884.2,11.04,121.78,'IS 1161:2014'); +INSERT INTO CHS VALUES(79,' CHS 355.6 x 8','350',355.6,8.0,68.58,87.36,90579.0,11172.0,10669.0,13201.37,742.48,12.29,151.11,'IS 1161:2014'); +INSERT INTO CHS VALUES(80,' CHS 355.6 x 10','350',355.6,10.0,85.23,108.57,88457.0,11172.0,10543.0,16223.5,912.46,12.22,149.42,'IS 1161:2014'); +INSERT INTO CHS VALUES(81,' CHS 355.6 x 12','350',355.6,12.0,101.68,129.53,86361.0,11172.0,10418.0,19139.47,1076.46,12.16,147.76,'IS 1161:2014'); +CREATE TABLE IF NOT EXISTS "Angles" ( + "Id" INTEGER, + "Designation" VARCHAR(50), + "Mass" REAL(10 , 2), + "Area" REAL(10 , 2), + "a" REAL(10 , 2), + "b" REAL(10 , 2), + "t" REAL(10 , 2), + "R1" REAL(10 , 2), + "R2" REAL(10 , 2) DEFAULT (null), + "Cz" REAL(10 , 2), + "Cy" REAL(10 , 2), + "Iz" REAL(10 , 2), + "Iy" REAL(10 , 2), + "Alpha" REAL(10 , 2), + "Iumax" REAL(10 , 2), + "Ivmin" REAL(10 , 2), + "rz" REAL(10 , 2), + "ry" REAL(10 , 2), + "rumax" REAL(10 , 2), + "rvmin" REAL(10 , 2), + "Zz" REAL(10 , 2), + "Zy" REAL(10 , 2), + "Zpz" REAL(10 , 2), + "Zpy" REAL(10 , 2), + "It" REAL(10 , 2), + "Source" VARCHAR(100), + "Type" VARCHAR(100), + PRIMARY KEY("Id") +); +INSERT INTO Angles VALUES(1,'20 x 20 x 3',0.9,1.14,20.0,20.0,3.0,4.0,0.0,0.6,0.6,0.4,0.4,0.79,0.64,0.17,0.59,0.59,0.75,0.39,0.29,0.29,0.52,0.53,0.033000000000000007105,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(2,'20 x 20 x 4',1.16,1.47,20.0,20.0,4.0,4.0,0.0,0.64,0.64,0.5,0.5,0.79,0.79,0.22,0.58,0.58,0.73,0.39,0.37,0.37,0.66,0.67,0.075999999999999996447,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(3,'25 x 25 x 3',1.14,1.45,25.0,25.0,3.0,4.5,0.0,0.73,0.73,0.83,0.83,0.79,1.3,0.35,0.75,0.75,0.95,0.49,0.46,0.46,0.83,0.84,0.042000000000000001776,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(4,'25 x 25 x 4',1.48,1.88,25.0,25.0,4.0,4.5,0.0,0.76,0.76,1.04,1.04,0.79,1.63,0.44,0.74,0.74,0.93,0.48,0.6,0.6,1.07,1.09,0.098000000000000024868,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(5,'25 x 25 x 5',1.8,2.29,25.0,25.0,5.0,4.5,0.0,0.8,0.8,1.23,1.23,0.79,1.92,0.54,0.73,0.73,0.92,0.48,0.72,0.72,1.3,1.31,0.18700000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(6,'30 x 30 x 3',1.38,1.76,30.0,30.0,3.0,5.0,0.0,0.85,0.85,1.47,1.47,0.79,2.32,0.62,0.91,0.91,1.15,0.59,0.68,0.68,1.22,1.23,0.050999999999999996447,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(7,'30 x 30 x 4',1.8,2.29,30.0,30.0,4.0,5.0,0.0,0.89,0.89,1.86,1.86,0.79,2.94,0.78,0.9,0.9,1.13,0.58,0.88,0.88,1.58,1.6,0.11899999999999999467,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(8,'30 x 30 x 5',2.2,2.8,30.0,30.0,5.0,5.0,0.0,0.93,0.93,2.22,2.22,0.79,3.49,0.95,0.89,0.89,1.12,0.58,1.07,1.07,1.92,1.94,0.22900000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(9,'35 x 35 x 3',1.62,2.06,35.0,35.0,3.0,5.0,0.0,0.97,0.97,2.38,2.38,0.79,3.77,0.99,1.07,1.07,1.35,0.69,0.94,0.94,1.69,1.7,0.06,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(10,'35 x 35 x 4',2.11,2.69,35.0,35.0,4.0,5.0,0.0,1.01,1.01,3.04,3.04,0.79,4.81,1.27,1.06,1.06,1.34,0.69,1.22,1.22,2.19,2.21,0.14,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(11,'35 x 35 x 5',2.59,3.3,35.0,35.0,5.0,5.0,0.0,1.05,1.05,3.65,3.65,0.79,5.76,1.54,1.05,1.05,1.32,0.68,1.49,1.49,2.68,2.69,0.27,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(12,'35 x 35 x 6',3.06,3.89,35.0,35.0,6.0,5.0,0.0,1.09,1.09,4.2,4.2,0.79,6.61,1.8,1.04,1.04,1.3,0.68,1.74,1.74,3.14,3.15,0.46,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(13,'40 x 40 x 3',1.86,2.37,40.0,40.0,3.0,5.5,0.0,1.09,1.09,3.61,3.61,0.79,5.72,1.51,1.23,1.23,1.55,0.8,1.24,1.24,2.22,2.24,0.069000000000000003552,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(14,'40 x 40 x 4',2.44,3.1,40.0,40.0,4.0,5.5,0.0,1.13,1.13,4.63,4.63,0.79,7.34,1.93,1.22,1.22,1.54,0.79,1.62,1.62,2.9,2.92,0.16200000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(15,'40 x 40 x 5',2.99,3.81,40.0,40.0,5.0,5.5,0.0,1.17,1.17,5.58,5.58,0.79,8.83,2.33,1.21,1.21,1.52,0.78,1.97,1.97,3.55,3.57,0.31200000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(16,'40 x 40 x 6',3.54,4.5,40.0,40.0,6.0,5.5,0.0,1.21,1.21,6.46,6.46,0.79,10.2,2.73,1.2,1.2,1.5,0.78,2.32,2.32,4.17,4.19,0.53200000000000002842,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(17,'45 x 45 x 3',2.1,2.67,45.0,45.0,3.0,5.5,0.0,1.22,1.22,5.2,5.2,0.79,8.2,2.17,1.39,1.39,1.76,0.9,1.58,1.58,2.84,2.86,0.078000000000000015987,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(18,'45 x 45 x 4',2.75,3.5,45.0,45.0,4.0,5.5,0.0,1.26,1.26,6.7,6.7,0.79,10.6,2.78,1.38,1.38,1.74,0.89,2.07,2.07,3.71,3.73,0.1830000000000000071,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(19,'45 x 45 x 5',3.39,4.31,45.0,45.0,5.0,5.5,0.0,1.3,1.3,8.1,8.1,0.79,12.8,3.37,1.37,1.37,1.72,0.88,2.53,2.53,4.55,4.57,0.35400000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(20,'45 x 45 x 6',4.01,5.1,45.0,45.0,6.0,5.5,0.0,1.34,1.34,9.42,9.42,0.79,14.9,3.94,1.36,1.36,1.71,0.88,2.98,2.98,5.36,5.38,0.60400000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(21,'50 x 50 x 3',2.34,2.99,50.0,50.0,3.0,6.0,0.0,1.34,1.34,7.21,7.21,0.79,11.4,3.01,1.55,1.55,1.96,1.0,1.97,1.97,3.53,3.55,0.086999999999999992894,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(22,'50 x 50 x 4',3.08,3.92,50.0,50.0,4.0,6.0,0.0,1.38,1.38,9.32,9.32,0.79,14.8,3.86,1.54,1.54,1.94,0.99,2.57,2.57,4.62,4.64,0.20400000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(23,'50 x 50 x 5',3.79,4.83,50.0,50.0,5.0,6.0,0.0,1.42,1.42,11.3,11.3,0.79,17.9,4.69,1.53,1.53,1.93,0.99,3.16,3.16,5.67,5.7,0.39500000000000001776,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(24,'50 x 50 x 6',4.49,5.72,50.0,50.0,6.0,6.0,0.0,1.46,1.46,13.2,13.2,0.79,20.8,5.48,1.52,1.52,1.91,0.98,3.72,3.72,6.69,6.71,0.67600000000000015631,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(25,'55 x 55 x 4',3.4,4.33,55.0,55.0,4.0,6.5,0.0,1.5,1.5,12.5,12.5,0.79,19.9,5.2,1.7,1.7,2.14,1.1,3.14,3.14,5.63,5.66,0.22600000000000002309,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(26,'55 x 55 x 5',4.19,5.34,55.0,55.0,5.0,6.5,0.0,1.54,1.54,15.2,15.2,0.79,24.2,6.31,1.69,1.69,2.13,1.09,3.85,3.85,6.92,6.95,0.43700000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(27,'55 x 55 x 6',4.97,6.33,55.0,55.0,6.0,6.5,0.0,1.58,1.58,17.8,17.8,0.79,28.2,7.39,1.68,1.68,2.11,1.08,4.55,4.55,8.17,8.2,0.74800000000000004263,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(28,'55 x 55 x 8',6.48,8.25,55.0,55.0,8.0,6.5,0.0,1.66,1.66,22.5,22.5,0.79,35.6,9.48,1.65,1.65,2.08,1.07,5.87,5.87,10.5,10.6,1.74,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(29,'60 x 60 x 4',3.71,4.73,60.0,60.0,4.0,6.5,0.0,1.63,1.63,16.4,16.4,0.79,26.0,6.8,1.86,1.86,2.35,1.2,3.76,3.76,6.74,6.77,0.24699999999999993072,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(30,'60 x 60 x 5',4.58,5.84,60.0,60.0,5.0,6.5,0.0,1.67,1.67,20.0,20.0,0.79,31.7,8.26,1.85,1.85,2.33,1.19,4.62,4.62,8.3,8.32,0.47900000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(31,'60 x 60 x 6',5.44,6.93,60.0,60.0,6.0,6.5,0.0,1.71,1.71,23.4,23.4,0.79,37.1,9.69,1.84,1.84,2.31,1.18,5.46,5.46,9.81,9.84,0.82,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(32,'60 x 60 x 8',7.1,9.05,60.0,60.0,8.0,6.5,0.0,1.78,1.78,29.8,29.8,0.79,47.1,12.4,1.81,1.81,2.28,1.17,7.06,7.06,12.7,12.7,1.91,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(33,'65 x 65 x 4',4.03,5.13,65.0,65.0,4.0,6.5,0.0,1.75,1.75,21.0,21.0,0.79,33.4,8.69,2.02,2.02,2.55,1.3,4.43,4.43,7.95,7.98,0.26800000000000001598,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(34,'65 x 65 x 5',4.98,6.34,65.0,65.0,5.0,6.5,0.0,1.79,1.79,25.7,25.7,0.79,40.8,10.6,2.01,2.01,2.54,1.29,5.45,5.45,9.8,9.83,0.52,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(35,'65 x 65 x 6',5.91,7.53,65.0,65.0,6.0,6.5,0.0,1.83,1.83,30.1,30.1,0.79,47.8,12.4,2.0,2.0,2.52,1.28,6.45,6.45,11.5,11.6,0.89199999999999999289,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(36,'65 x 65 x 8',7.73,9.85,65.0,65.0,8.0,6.5,0.0,1.91,1.91,38.4,38.4,0.79,60.8,16.0,1.97,1.97,2.48,1.27,8.36,8.36,15.0,15.0,2.08,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(37,'70 x 70 x 5',5.38,6.86,70.0,70.0,5.0,7.0,0.0,1.92,1.92,32.3,32.3,0.79,51.3,13.3,2.17,2.17,2.74,1.39,6.36,6.36,11.4,11.4,0.56200000000000009947,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(38,'70 x 70 x 6',6.39,8.15,70.0,70.0,6.0,7.0,0.0,1.96,1.96,38.0,38.0,0.79,60.3,15.6,2.16,2.16,2.72,1.39,7.53,7.53,13.5,13.5,0.96400000000000005684,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(39,'70 x 70 x 8',8.37,10.6,70.0,70.0,8.0,7.0,0.0,2.03,2.03,48.5,48.5,0.79,76.9,20.1,2.13,2.13,2.69,1.37,9.77,9.77,17.5,17.6,2.25,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(40,'70 x 70 x 10',10.29,13.1,70.0,70.0,10.0,7.0,0.0,2.11,2.11,58.3,58.3,0.79,92.1,24.4,2.11,2.11,2.65,1.37,11.9,11.9,21.4,21.5,4.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(41,'75 x 75 x 5',5.77,7.36,75.0,75.0,5.0,7.0,0.0,2.04,2.04,40.0,40.0,0.79,63.6,16.5,2.33,2.33,2.94,1.5,7.3,7.3,13.2,13.2,0.60400000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(42,'75 x 75 x 6',6.86,8.75,75.0,75.0,6.0,7.0,0.0,2.08,2.08,47.1,47.1,0.79,74.8,19.4,2.32,2.32,2.92,1.49,8.7,8.7,15.6,15.6,1.03,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(43,'75 x 75 x 8',9.0,11.4,75.0,75.0,8.0,7.0,0.0,2.16,2.16,60.3,60.3,0.79,95.7,24.9,2.29,2.29,2.89,1.47,11.3,11.3,20.3,20.4,2.42,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(44,'75 x 75 x 10',11.07,14.1,75.0,75.0,10.0,7.0,0.0,2.23,2.23,72.6,72.6,0.79,114.0,30.3,2.27,2.27,2.85,1.47,13.8,13.8,24.8,24.9,4.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(45,'80 x 80 x 6',7.36,9.38,80.0,80.0,6.0,8.0,0.0,2.2,2.2,57.6,57.6,0.79,91.4,23.7,2.48,2.48,3.12,1.59,9.9,9.9,17.8,17.9,1.1,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(46,'80 x 80 x 8',9.65,12.3,80.0,80.0,8.0,8.0,0.0,2.28,2.28,74.0,74.0,0.79,117.0,30.5,2.45,2.45,3.09,1.58,12.9,12.9,23.3,23.3,2.59,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(47,'80 x 80 x 10',11.88,15.1,80.0,80.0,10.0,8.0,0.0,2.36,2.36,89.2,89.2,0.79,141.0,37.1,2.43,2.43,3.05,1.57,15.8,15.8,28.4,28.5,5.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(48,'80 x 80 x 12',14.05,17.9,80.0,80.0,12.0,8.0,0.0,2.43,2.43,103.0,103.0,0.79,163.0,43.5,2.4,2.4,3.02,1.56,18.5,18.5,33.4,33.5,8.52,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(49,'90 x 90 x 6',8.32,10.6,90.0,90.0,6.0,8.5,0.0,2.45,2.45,83.0,83.0,0.79,131.0,34.2,2.8,2.8,3.53,1.8,12.7,12.7,22.8,22.8,1.25,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(50,'90 x 90 x 8',10.92,13.9,90.0,90.0,8.0,8.5,0.0,2.53,2.53,107.0,107.0,0.79,170.0,44.1,2.77,2.77,3.5,1.78,16.5,16.5,29.7,29.8,2.93,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(51,'90 x 90 x 10',13.47,17.1,90.0,90.0,10.0,8.5,0.0,2.6,2.6,129.0,129.0,0.79,205.0,53.6,2.75,2.75,3.46,1.77,20.2,20.2,36.4,36.5,5.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(52,'90 x 90 x 12',15.95,20.3,90.0,90.0,12.0,8.5,0.0,2.68,2.68,150.0,150.0,0.79,238.0,62.8,2.72,2.72,3.42,1.76,23.8,23.8,42.9,43.0,9.67,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(53,'100 x 100 x 6',9.26,11.8,100.0,100.0,6.0,8.5,0.0,2.7,2.7,115.0,115.0,0.79,182.0,47.2,3.12,3.12,3.94,2.0,15.7,15.7,28.3,28.3,1.39,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(54,'100 x 100 x 8',12.18,15.5,100.0,100.0,8.0,8.5,0.0,2.78,2.78,148.0,148.0,0.79,236.0,61.0,3.1,3.1,3.9,1.98,20.6,20.6,37.0,37.1,3.27,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(55,'100 x 100 x 10',15.04,19.1,100.0,100.0,10.0,8.5,0.0,2.85,2.85,180.0,180.0,0.79,286.0,74.3,3.07,3.07,3.87,1.97,25.3,25.3,45.4,45.5,6.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(56,'100 x 100 x 12',17.83,22.7,100.0,100.0,12.0,8.5,0.0,2.93,2.93,210.0,210.0,0.79,333.0,87.2,3.04,3.04,3.83,1.96,29.8,29.8,53.6,53.7,10.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(57,'110 x 110 x 8',13.4,17.0,110.0,110.0,8.0,10.0,4.8,3.0,3.0,196.0,196.0,0.79,312.0,80.7,3.39,3.39,4.28,2.17,24.6,24.6,44.6,44.7,3.61,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(58,'110 x 110 x 10',16.58,21.1,110.0,110.0,10.0,10.0,4.8,3.09,3.09,240.0,240.0,0.79,381.0,98.6,3.37,3.37,4.25,2.16,30.4,30.4,54.9,55.0,7.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(59,'110 x 110 x 12',19.68,25.0,110.0,110.0,12.0,10.0,4.8,3.17,3.17,281.0,281.0,0.79,446.0,116.0,3.35,3.35,4.22,2.15,35.9,35.9,64.9,65.1,11.9,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(60,'110 x 110 x 16',25.71,32.7,110.0,110.0,16.0,10.0,4.8,3.32,3.32,357.0,357.0,0.79,565.0,149.0,3.3,3.3,4.15,2.14,46.5,46.5,84.1,84.2,27.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(61,'130 x 130 x 8',15.92,20.2,130.0,130.0,8.0,10.0,4.8,3.5,3.5,330.0,330.0,0.79,526.0,135.0,4.04,4.04,5.1,2.58,34.8,34.8,63.0,63.1,4.3,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(62,'130 x130 x 10',19.72,25.1,130.0,130.0,10.0,10.0,4.8,3.59,3.59,405.0,405.0,0.79,644.0,165.0,4.02,4.02,5.07,2.57,43.1,43.1,77.8,77.9,8.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(63,'130 x130 x 12',23.45,29.8,130.0,130.0,12.0,10.0,4.8,3.67,3.67,476.0,476.0,0.79,757.0,195.0,3.99,3.99,5.04,2.56,51.0,51.0,92.2,92.3,14.2,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(64,'130 x130 x 16',30.74,39.1,130.0,130.0,16.0,10.0,4.8,3.82,3.82,609.0,609.0,0.79,966.0,252.0,3.94,3.94,4.97,2.54,66.3,66.3,119.0,120.0,33.3,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(65,'150 x 150 x 10',22.93,29.2,150.0,150.0,10.0,12.0,4.8,4.08,4.08,633.0,633.0,0.79,1000.0,259.0,4.66,4.66,5.87,2.98,58.0,58.0,104.0,104.0,9.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(66,'150 x 150 x 12',27.29,34.7,150.0,150.0,12.0,12.0,4.8,4.16,4.16,746.0,746.0,0.79,1180.0,305.0,4.63,4.63,5.84,2.96,68.8,68.8,124.0,124.0,16.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(67,'150 x 150 x 16',35.84,45.6,150.0,150.0,16.0,12.0,4.8,4.31,4.31,958.0,958.0,0.79,1520.0,394.0,4.58,4.58,5.78,2.94,89.7,89.7,162.0,162.0,38.7,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(68,'150 x 150 x 20',44.12,56.2,150.0,150.0,20.0,12.0,4.8,4.46,4.46,1150.0,1150.0,0.79,1830.0,480.0,4.53,4.53,5.71,2.92,109.0,109.0,198.0,198.0,74.6,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(69,'200 x 200 x 12',36.85,46.9,200.0,200.0,12.0,15.0,4.8,5.39,5.39,1820.0,1820.0,0.79,2900.0,746.0,6.24,6.24,7.87,3.99,125.0,125.0,225.0,225.0,22.3,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(70,'200 x 200 x 16',48.53,61.8,200.0,200.0,16.0,15.0,4.8,5.56,5.56,2360.0,2360.0,0.79,3760.0,967.0,6.19,6.19,7.8,3.96,163.0,163.0,295.0,295.0,52.4,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(71,'200 x 200 x 20',59.96,76.3,200.0,200.0,20.0,15.0,4.8,5.71,5.71,2870.0,2870.0,0.79,4560.0,1180.0,6.13,6.13,7.73,3.93,201.0,201.0,362.0,363.0,101.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(72,'200 x 200 x 25',73.9,94.1,200.0,200.0,25.0,15.0,4.8,5.9,5.9,3470.0,3470.0,0.79,5500.0,1430.0,6.07,6.07,7.65,3.91,246.0,246.0,443.0,444.0,195.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(73,'50 x 50 x 7',5.17,6.59,50.0,50.0,7.0,6.0,0.0,1.5,1.5,14.9,14.9,0.79,23.6,6.27,1.51,1.51,1.89,0.98,4.26,4.26,7.67,7.7,1.06,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(74,'50 x 50 x 8',5.84,7.44,50.0,50.0,8.0,6.0,0.0,1.54,1.54,16.6,16.6,0.79,26.2,7.03,1.49,1.49,1.88,0.97,4.79,4.79,8.62,8.65,1.57,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(75,'55 x 55 x 10',7.92,10.0,55.0,55.0,10.0,6.5,0.0,1.73,1.73,26.8,26.8,0.79,42.1,11.5,1.63,1.63,2.04,1.07,7.11,7.11,12.8,12.8,3.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(76,'60 x 60 x 10',8.71,11.0,60.0,60.0,10.0,6.5,0.0,1.86,1.86,35.5,35.5,0.79,55.9,15.1,1.79,1.79,2.25,1.17,8.57,8.57,15.4,15.4,3.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(77,'65 x 65 x 10',9.49,12.0,65.0,65.0,10.0,6.5,0.0,1.98,1.98,45.9,45.9,0.79,72.5,19.4,1.95,1.95,2.45,1.27,10.1,10.1,18.3,18.3,4.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(78,'70 x 70 x 7',7.39,9.42,70.0,70.0,7.0,7.0,0.0,2.0,2.0,43.4,43.4,0.79,68.8,17.9,2.15,2.15,2.7,1.38,8.66,8.66,15.5,15.6,1.52,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(79,'100 x 100 x 7',10.73,13.6,100.0,100.0,7.0,8.5,0.0,2.74,2.74,132.0,132.0,0.79,210.0,54.2,3.11,3.11,3.92,1.99,18.2,18.2,32.7,32.7,2.2,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(80,'100 x 100 x 15',21.91,27.9,100.0,100.0,15.0,8.5,0.0,3.04,3.04,252.0,252.0,0.79,398.0,106.0,3.01,3.01,3.78,1.95,36.2,36.2,65.3,65.4,20.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(81,'120 x 120 x 8',14.66,18.6,120.0,120.0,8.0,10.0,4.8,3.25,3.25,258.0,258.0,0.79,410.0,105.0,3.72,3.72,4.69,2.38,29.5,29.5,53.4,53.5,3.95,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(82,'120 x 120 x 10',18.15,23.1,120.0,120.0,10.0,10.0,4.8,3.34,3.34,315.0,315.0,0.79,501.0,129.0,3.69,3.69,4.66,2.36,36.4,36.4,65.9,66.0,7.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(83,'120 x 120 x 12',21.57,27.4,120.0,120.0,12.0,10.0,4.8,3.42,3.42,370.0,370.0,0.79,588.0,152.0,3.67,3.67,4.63,2.35,43.1,43.1,78.0,78.1,13.1,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(84,'120 x 120 x 15',26.58,33.8,120.0,120.0,15.0,10.0,4.8,3.53,3.53,447.0,447.0,0.79,709.0,185.0,3.64,3.64,4.58,2.34,52.8,52.8,95.5,95.6,25.3,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(85,'130 x 130 x 9',17.82,22.7,130.0,130.0,9.0,10.0,4.8,3.55,3.55,368.0,368.0,0.79,586.0,150.0,4.03,4.03,5.08,2.57,39.0,39.0,70.5,70.6,6.09,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(86,'150 x 150 x 15',33.72,42.9,150.0,150.0,15.0,12.0,4.8,4.28,4.28,907.0,907.0,0.79,1440.0,372.0,4.6,4.6,5.79,2.95,84.6,84.6,152.0,152.0,32.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(87,'150 x 150 x 18',40.01,50.9,150.0,150.0,18.0,12.0,4.8,4.39,4.39,1050.0,1050.0,0.79,1680.0,437.0,4.56,4.56,5.74,2.93,99.8,99.8,180.0,180.0,54.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(88,'180 x 180 x 15',41.09,52.3,180.0,180.0,15.0,18.0,4.8,5.0,5.0,1610.0,1610.0,0.79,2550.0,663.0,5.55,5.55,6.99,3.56,123.0,123.0,223.0,223.0,38.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(89,'180 x 180 x 18',48.79,62.1,180.0,180.0,18.0,18.0,4.8,5.12,5.12,1880.0,1880.0,0.79,2990.0,778.0,5.51,5.51,6.94,3.54,146.0,146.0,264.0,264.0,66.4,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(90,'180 x 180 x 20',53.85,68.6,180.0,180.0,20.0,18.0,4.8,5.2,5.2,2060.0,2060.0,0.79,3270.0,853.0,5.49,5.49,6.91,3.53,161.0,161.0,290.0,291.0,90.6,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(91,'200 x 200 x 24',71.31,90.8,200.0,200.0,24.0,18.0,4.8,5.85,5.85,3350.0,3350.0,0.79,5320.0,1390.0,6.08,6.08,7.65,3.91,237.0,237.0,427.0,428.0,173.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(92,'30 x 20 x 3',1.14,1.45,30.0,20.0,3.0,4.5,0.0,0.99,0.51,1.29,0.46,1.05,1.47,0.27,0.94,0.56,1.01,0.43,0.64,0.31,1.16,0.56,0.042000000000000001776,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(93,'30 x 20 x 4',1.48,1.88,30.0,20.0,4.0,4.5,0.0,1.04,0.55,1.63,0.57,0.4,1.85,0.34,0.93,0.55,0.99,0.43,0.83,0.39,1.48,0.73,0.098000000000000024868,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(94,'30 x 20 x 5',1.8,2.29,30.0,20.0,5.0,4.5,0.0,1.07,0.58,1.93,0.67,0.39,2.19,0.41,0.92,0.54,0.98,0.42,1.0,0.47,1.79,0.9,0.18700000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(95,'40 x 25 x 3',1.5,1.91,40.0,25.0,3.0,5.0,0.0,1.32,0.59,3.11,0.94,0.37,3.48,0.57,1.27,0.7,1.35,0.54,1.16,0.49,2.08,0.9,0.055,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(96,'40 x 25 x 4',1.96,2.49,40.0,25.0,4.0,5.0,0.0,1.36,0.63,3.97,1.19,0.36,4.44,0.72,1.26,0.69,1.33,0.54,1.5,0.64,2.69,1.18,0.13,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(97,'40 x 25 x 5',2.4,3.05,40.0,25.0,5.0,5.0,0.0,1.4,0.67,4.76,1.42,0.36,5.31,0.87,1.25,0.68,1.32,0.53,1.83,0.77,3.27,1.45,0.25,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(98,'40 x 25 x 6',2.82,3.59,40.0,25.0,6.0,5.0,0.0,1.44,0.7,5.5,1.62,0.35,6.1,1.02,1.24,0.67,1.3,0.53,2.15,0.9,3.81,1.72,0.42400000000000002131,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(99,'45 x 30 x 3',1.74,2.21,45.0,30.0,3.0,5.0,0.0,1.44,0.71,4.57,1.65,0.41,5.26,0.96,1.44,0.86,1.54,0.66,1.49,0.72,2.7,1.29,0.064000000000000003552,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(100,'45 x 30 x 4',2.27,2.89,45.0,30.0,4.0,5.0,0.0,1.48,0.74,5.87,2.1,0.41,6.75,1.22,1.42,0.85,1.53,0.65,1.95,0.93,3.5,1.69,0.15099999999999999644,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(101,'45 x 30 x 5',2.79,3.55,45.0,30.0,5.0,5.0,0.0,1.52,0.78,7.08,2.51,0.4,8.11,1.48,1.41,0.84,1.51,0.64,2.38,1.13,4.27,2.08,0.29099999999999997868,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(102,'45 x 30 x 6',3.29,4.19,45.0,30.0,6.0,5.0,0.0,1.56,0.82,8.21,2.89,0.4,9.37,1.73,1.4,0.83,1.49,0.64,2.79,1.32,5.0,2.46,0.49599999999999999644,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(103,'50 x 30 x 3',1.86,2.37,50.0,30.0,3.0,5.5,0.0,1.64,0.67,6.13,1.69,0.35,6.79,1.03,1.61,0.84,1.69,0.66,1.83,0.73,3.28,1.31,0.069000000000000003552,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(104,'50 x 30 x 4',2.44,3.1,50.0,30.0,4.0,5.5,0.0,1.69,0.71,7.89,2.15,0.34,8.73,1.32,1.59,0.83,1.68,0.65,2.38,0.94,4.26,1.72,0.16200000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(105,'50 x 30 x 5',2.99,3.81,50.0,30.0,5.0,5.5,0.0,1.73,0.75,9.53,2.58,0.34,10.5,1.59,1.58,0.82,1.66,0.65,2.92,1.15,5.19,2.13,0.31200000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(106,'50 x 30 x 6',3.54,4.5,50.0,30.0,6.0,5.5,0.0,1.77,0.79,11.1,2.97,0.33,12.2,1.86,1.57,0.81,1.64,0.64,3.43,1.34,6.09,2.52,0.53200000000000002842,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(107,'60 x 40 x 5',3.79,4.83,60.0,40.0,5.0,6.0,0.0,1.97,0.98,17.5,6.28,0.41,20.2,3.65,1.91,1.14,2.04,0.87,4.35,2.08,7.83,3.77,0.39500000000000001776,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(108,'60 x 40 x 6',4.49,5.72,60.0,40.0,6.0,6.0,0.0,2.01,1.02,20.5,7.29,0.41,23.5,4.26,1.89,1.13,2.03,0.86,5.13,2.45,9.21,4.47,0.67600000000000015631,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(109,'60 x 40 x 8',5.84,7.44,60.0,40.0,8.0,6.0,0.0,2.08,1.09,25.9,9.12,0.4,29.6,5.45,1.87,1.11,1.99,0.86,6.62,3.14,11.8,5.83,1.57,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(110,'65 x 45 x 5',4.18,5.33,65.0,45.0,5.0,6.0,0.0,2.09,1.1,22.8,9.02,0.44,26.7,5.12,2.07,1.3,2.24,0.98,5.16,2.65,9.33,4.77,0.43700000000000001065,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(111,'65 x 45 x 6',4.96,6.32,65.0,45.0,6.0,6.0,0.0,2.13,1.14,26.7,10.5,0.44,31.2,5.99,2.06,1.29,2.22,0.97,6.1,3.12,11.0,5.66,0.74800000000000004263,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(112,'65 x 45 x 8',6.47,8.24,65.0,45.0,8.0,6.0,0.0,2.2,1.21,33.9,13.2,0.43,39.5,7.66,2.03,1.27,2.19,0.96,7.89,4.02,14.1,7.39,1.74,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(113,'70 x 45 x 5',4.39,5.59,70.0,45.0,5.0,6.5,0.0,2.29,1.06,28.0,9.2,0.39,31.8,5.42,2.24,1.28,2.39,0.98,5.95,2.68,10.7,4.82,0.4580000000000000071,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(114,'70 x 45 x 6',5.21,6.63,70.0,45.0,6.0,6.5,0.0,2.33,1.1,32.8,10.7,0.39,37.2,6.34,2.23,1.27,2.37,0.98,7.04,3.15,12.6,5.72,0.78399999999999998578,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(115,'70 x 45 x 8',6.79,8.65,70.0,45.0,8.0,6.5,0.0,2.41,1.18,41.8,13.5,0.38,47.2,8.1,2.2,1.25,2.34,0.97,9.12,4.06,16.3,7.5,1.82,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(116,'70 x 45 x 10',8.31,10.5,70.0,45.0,10.0,6.5,0.0,2.49,1.25,50.0,16.0,0.37,56.2,9.81,2.17,1.23,2.3,0.96,11.0,4.91,19.7,9.22,3.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(117,'75 x 50 x 5',4.78,6.09,75.0,50.0,5.0,6.5,0.0,2.41,1.18,35.1,12.7,0.41,40.5,7.32,2.4,1.44,2.58,1.1,6.9,3.32,12.4,5.95,0.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(118,'75 x 50 x 6',5.68,7.23,75.0,50.0,6.0,6.5,0.0,2.45,1.22,41.2,14.8,0.41,47.5,8.57,2.39,1.43,2.56,1.09,8.17,3.92,14.7,7.07,0.85600000000000004973,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(119,'75 x 50 x 8',7.42,9.45,75.0,50.0,8.0,6.5,0.0,2.53,1.29,52.7,18.7,0.41,60.5,10.9,2.36,1.41,2.53,1.08,10.6,5.05,19.0,9.25,1.99,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(120,'75 x 50 x 10',9.1,11.5,75.0,50.0,10.0,6.5,0.0,2.61,1.37,63.2,22.3,0.4,72.2,13.3,2.34,1.39,2.5,1.07,12.9,6.13,23.1,11.3,3.83,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(121,'80 x 50 x 5',4.99,6.36,80.0,50.0,5.0,7.0,0.0,2.62,1.14,42.0,12.9,0.37,47.3,7.68,2.57,1.43,2.73,1.1,7.81,3.34,14.0,5.99,0.52,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(122,'80 x 50 x 6',5.92,7.55,80.0,50.0,6.0,7.0,0.0,2.66,1.18,49.4,15.1,0.37,55.5,8.99,2.56,1.41,2.71,1.09,9.25,3.95,16.5,7.13,0.89199999999999999289,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(123,'80 x 50 x 8',7.74,9.87,80.0,50.0,8.0,7.0,0.0,2.74,1.26,63.2,19.1,0.37,70.8,11.5,2.53,1.39,2.68,1.08,12.0,5.09,21.4,9.36,2.08,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(124,'80 x 50 x 10',9.5,12.1,80.0,50.0,10.0,7.0,0.0,2.82,1.33,76.0,22.7,0.36,84.7,13.9,2.5,1.37,2.65,1.07,14.6,6.18,26.0,11.5,4.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(125,'90 x 60 x 6',6.88,8.76,90.0,60.0,6.0,7.5,0.0,2.9,1.42,72.8,26.3,0.41,84.0,15.2,2.88,1.73,3.1,1.32,11.9,5.74,21.5,10.2,1.03,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(126,'90 x 60 x 8',9.01,11.4,90.0,60.0,8.0,7.5,0.0,2.98,1.49,93.6,33.5,0.41,107.0,19.5,2.86,1.71,3.06,1.3,15.5,7.44,27.9,13.4,2.42,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(127,'90 x 60 x 10',11.08,14.1,90.0,60.0,10.0,7.5,0.0,3.06,1.57,113.0,40.1,0.41,129.0,23.6,2.83,1.69,3.03,1.29,19.0,9.05,34.1,16.6,4.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(128,'90 x 60 x 12',13.09,16.6,90.0,60.0,12.0,7.5,0.0,3.13,1.64,131.0,46.2,0.4,149.0,27.6,2.8,1.66,3.0,1.29,22.3,10.6,39.9,19.7,7.94,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(129,'100 x 65 x 6',7.6,9.68,100.0,65.0,6.0,8.0,0.0,3.22,1.5,100.0,34.0,0.4,114.0,19.8,3.22,1.88,3.44,1.43,14.8,6.8,26.6,12.1,1.14,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(130,'100 x 65 x 8',9.97,12.7,100.0,65.0,8.0,8.0,0.0,3.3,1.57,129.0,43.5,0.4,147.0,25.5,3.19,1.85,3.4,1.42,19.3,8.8,34.6,15.9,2.67,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(131,'100 x 65 x 10',12.28,15.6,100.0,65.0,10.0,8.0,0.0,3.38,1.65,156.0,52.2,0.39,177.0,30.9,3.16,1.83,3.37,1.4,23.6,10.8,42.3,19.7,5.16,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(132,'100 x 75 x 6',8.08,10.3,100.0,75.0,6.0,8.5,0.0,3.05,1.82,105.0,51.2,0.5,128.0,27.6,3.19,2.23,3.54,1.64,15.1,9.0,27.4,16.0,1.21,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(133,'100 x 75 x 8',10.61,13.5,100.0,75.0,8.0,8.5,0.0,3.13,1.89,135.0,65.7,0.5,165.0,35.5,3.17,2.21,3.5,1.62,19.7,11.7,35.8,21.0,2.85,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(134,'100 x 75 x 10',13.07,16.6,100.0,75.0,10.0,8.5,0.0,3.21,1.97,164.0,79.2,0.5,200.0,43.0,3.14,2.18,3.47,1.61,24.2,14.3,43.8,25.9,5.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(135,'100 x 75 x 12',15.48,19.7,100.0,75.0,12.0,8.5,0.0,3.28,2.04,191.0,91.7,0.5,232.0,50.4,3.11,2.16,3.43,1.6,28.5,16.8,51.4,30.6,9.38,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(136,'125 x 75 x 6',9.27,11.8,125.0,75.0,6.0,9.0,0.0,4.08,1.62,194.0,54.3,0.35,215.0,32.7,4.05,2.14,4.27,1.66,23.1,9.2,41.3,16.4,1.39,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(137,'125 x 75 x 8',12.19,15.5,125.0,75.0,8.0,9.0,0.0,4.17,1.7,251.0,69.7,0.35,279.0,42.1,4.03,2.12,4.24,1.65,30.2,12.0,53.9,21.6,3.27,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(138,'125 x 75 x 10',15.05,19.1,125.0,75.0,10.0,9.0,0.0,4.26,1.78,306.0,84.1,0.35,339.0,51.0,4.0,2.09,4.21,1.63,37.2,14.7,66.2,26.7,6.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(139,'125 x 95 x 6',10.14,12.9,125.0,95.0,6.0,9.0,4.8,3.72,2.24,205.0,103.0,0.52,254.0,55.0,3.99,2.83,4.44,2.06,23.4,14.3,42.9,25.5,1.54,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(140,'125 x 95 x 8',13.37,17.0,125.0,95.0,8.0,9.0,4.8,3.8,2.32,268.0,134.0,0.52,331.0,71.4,3.97,2.81,4.41,2.05,30.9,18.8,56.4,33.7,3.61,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(141,'125 x 95 x 10',16.54,21.0,125.0,95.0,10.0,9.0,4.8,3.89,2.4,328.0,164.0,0.51,404.0,87.3,3.94,2.79,4.38,2.04,38.1,23.1,69.4,41.7,7.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(142,'125 x 95 x 12',19.65,25.0,125.0,95.0,12.0,9.0,4.8,3.97,2.48,384.0,191.0,0.51,473.0,102.0,3.92,2.77,4.35,2.02,45.1,27.3,82.0,49.5,11.9,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(143,'150 x 115 x 8',16.27,20.7,150.0,115.0,8.0,11.0,4.8,4.48,2.76,474.0,244.0,0.52,589.0,128.0,4.78,3.43,5.34,2.49,45.1,27.9,82.4,50.0,4.38,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(144,'150 x 115 x 10',20.14,25.6,150.0,115.0,10.0,11.0,4.8,4.57,2.84,581.0,298.0,0.52,722.0,157.0,4.76,3.41,5.31,2.48,55.8,34.5,101.0,61.9,8.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(145,'150 x 115 x 12',23.96,30.5,150.0,115.0,12.0,11.0,4.8,4.65,2.92,684.0,350.0,0.52,849.0,185.0,4.74,3.39,5.28,2.47,66.2,40.8,120.0,73.5,14.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(146,'150 x 115 x 16',31.4,40.0,150.0,115.0,16.0,11.0,4.8,4.81,3.07,878.0,446.0,0.52,1080.0,239.0,4.69,3.34,5.21,2.44,86.2,53.0,156.0,96.1,33.9,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(147,'200 x 100 x 10',22.93,29.2,200.0,100.0,10.0,12.0,4.8,6.98,2.03,1220.0,214.0,0.26,1300.0,137.0,6.48,2.71,6.68,2.17,94.3,26.9,165.0,48.7,9.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(148,'200 x 100 x 12',27.29,34.7,200.0,100.0,12.0,12.0,4.8,7.07,2.11,1440.0,251.0,0.26,1530.0,161.0,6.46,2.69,6.65,2.15,112.0,31.9,196.0,58.3,16.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(149,'200 x 100 x 16',35.84,45.6,200.0,100.0,16.0,12.0,4.8,7.23,2.27,1870.0,319.0,0.25,1980.0,207.0,6.4,2.65,6.59,2.13,146.0,41.3,255.0,77.5,38.7,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(150,'200 x 150 x 10',26.92,34.2,200.0,150.0,10.0,13.5,4.8,6.02,3.55,1400.0,688.0,0.51,1720.0,368.0,6.41,4.48,7.1,3.28,100.0,60.2,183.0,107.0,11.3,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(151,'200 x 150 x 12',32.07,40.8,200.0,150.0,12.0,13.5,4.8,6.11,3.63,1660.0,812.0,0.51,2040.0,433.0,6.39,4.46,7.07,3.26,119.0,71.4,218.0,127.0,19.4,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(152,'200 x 150 x 16',42.18,53.7,200.0,150.0,16.0,13.5,4.8,6.27,3.79,2150.0,1040.0,0.5,2630.0,560.0,6.33,4.41,7.01,3.23,156.0,93.2,285.0,167.0,45.6,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(153,'200 x 150 x 20',52.04,66.2,200.0,150.0,20.0,13.5,4.8,6.42,3.94,2610.0,1260.0,0.5,3190.0,682.0,6.28,4.36,6.94,3.21,192.0,114.0,349.0,206.0,88.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(154,'40 x 20 x 3',1.37,1.74,40.0,20.0,3.0,4.0,0.0,1.43,0.45,2.9,0.49,0.25,3.04,0.32,1.28,0.53,1.32,0.43,1.11,0.32,1.95,0.59,0.050999999999999996447,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(155,'40 x 20 x 4',1.79,2.27,40.0,20.0,4.0,4.0,0.0,1.47,0.49,3.7,0.62,0.25,3.86,0.41,1.27,0.52,1.3,0.42,1.45,0.41,2.52,0.78,0.11899999999999999467,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(156,'40 x 20 x 5',2.19,2.78,40.0,20.0,5.0,4.0,0.0,1.51,0.52,4.4,0.73,0.24,4.62,0.49,1.25,0.51,1.29,0.42,1.76,0.49,3.05,0.97,0.22900000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(157,'60 x 30 x 5',3.4,4.33,60.0,30.0,5.0,6.0,0.0,2.16,0.69,15.9,2.7,0.25,16.8,1.76,1.92,0.79,1.97,0.64,4.14,1.17,7.24,2.21,0.35400000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(158,'60 x 30 x 6',4.02,5.12,60.0,30.0,6.0,6.0,0.0,2.21,0.73,18.5,3.11,0.25,19.6,2.06,1.9,0.78,1.96,0.63,4.88,1.37,8.5,2.64,0.60400000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(159,'60 x 40 x 7',5.17,6.59,60.0,40.0,7.0,6.0,0.0,2.05,1.06,23.3,8.23,0.4,26.6,4.86,1.88,1.12,2.01,0.86,5.89,2.8,10.5,5.16,1.06,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(160,'65 x 50 x 5',4.38,5.58,65.0,50.0,5.0,6.0,0.0,2.0,1.26,23.6,12.2,0.52,29.3,6.48,2.06,1.48,2.29,1.08,5.25,3.27,9.53,5.85,0.4580000000000000071,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(161,'65 x 50 x 6',5.19,6.62,65.0,50.0,6.0,6.0,0.0,2.04,1.3,27.6,14.2,0.52,34.3,7.59,2.04,1.47,2.28,1.07,6.2,3.85,11.2,6.93,0.78399999999999998578,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(162,'65 x 50 x 7',6.0,7.64,65.0,50.0,7.0,6.0,0.0,2.08,1.34,31.5,16.2,0.52,39.0,8.67,2.03,1.45,2.26,1.07,7.13,4.42,12.9,7.99,1.23,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(163,'65 x 50 x 8',6.78,8.64,65.0,50.0,8.0,6.0,0.0,2.12,1.38,35.2,18.0,0.52,43.4,9.72,2.02,1.44,2.24,1.06,8.03,4.97,14.5,9.03,1.82,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(164,'70 x 50 x 5',4.57,5.83,70.0,50.0,5.0,6.0,0.0,2.21,1.22,29.0,12.5,0.46,34.5,6.92,2.23,1.46,2.43,1.09,6.05,3.3,10.9,5.9,0.47900000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(165,'70 x 50 x 6',5.43,6.92,70.0,50.0,6.0,6.0,0.0,2.25,1.26,34.0,14.5,0.46,40.4,8.11,2.22,1.45,2.42,1.08,7.16,3.89,12.9,7.0,0.82,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(166,'70 x 50 x 7',6.27,7.99,70.0,50.0,7.0,6.0,0.0,2.29,1.3,38.8,16.5,0.46,46.0,9.26,2.2,1.44,2.4,1.08,8.23,4.46,14.8,8.08,1.29,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(167,'70 x 50 x 8',7.09,9.04,70.0,50.0,8.0,6.0,0.0,2.33,1.33,43.4,18.4,0.46,51.4,10.3,2.19,1.43,2.38,1.07,9.28,5.01,16.7,9.14,1.91,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(168,'75 x 50 x 7',6.57,8.37,75.0,50.0,7.0,7.0,0.0,2.49,1.26,47.1,16.8,0.41,54.2,9.8,2.37,1.42,2.54,1.08,9.41,4.49,16.9,8.17,1.34,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(169,'80 x 40 x 5',4.6,5.86,80.0,40.0,5.0,7.0,0.0,2.82,0.86,39.0,6.74,0.26,41.4,4.36,2.58,1.07,2.66,0.86,7.53,2.14,13.1,3.94,0.47900000000000000355,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(170,'80 x 40 x 6',5.45,6.95,80.0,40.0,6.0,7.0,0.0,2.86,0.89,45.7,7.84,0.25,48.5,5.09,2.57,1.06,2.64,0.86,8.9,2.52,15.5,4.7,0.82,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(171,'80 x 40 x 7',6.29,8.02,80.0,40.0,7.0,7.0,0.0,2.91,0.93,52.2,8.87,0.25,55.3,5.8,2.55,1.05,2.63,0.85,10.2,2.89,17.8,5.47,1.29,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(172,'80 x 40 x 8',7.12,9.07,80.0,40.0,8.0,7.0,0.0,2.95,0.97,58.4,9.84,0.25,61.7,6.5,2.54,1.04,2.61,0.85,11.5,3.25,20.1,6.24,1.91,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(173,'80 x 60 x 6',6.42,8.18,80.0,60.0,6.0,8.0,0.0,2.48,1.5,52.6,25.5,0.5,64.3,13.8,2.54,1.77,2.8,1.3,9.5,5.7,17.3,10.1,0.96400000000000005684,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(174,'80 x 60 x 7',7.42,9.45,80.0,60.0,7.0,8.0,0.0,2.52,1.54,60.1,29.1,0.5,73.4,15.8,2.52,1.75,2.79,1.29,11.0,6.5,19.9,11.7,1.52,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(175,'80 x 60 x 8',8.4,10.7,80.0,60.0,8.0,8.0,0.0,2.56,1.57,67.4,32.5,0.5,82.2,17.7,2.51,1.74,2.77,1.29,12.4,7.3,22.4,13.3,2.25,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(176,'90 x 65 x 6',7.13,9.08,90.0,65.0,6.0,8.0,0.0,2.81,1.57,74.8,33.1,0.47,89.7,18.3,2.87,1.91,3.14,1.42,12.1,6.7,21.9,12.0,1.07,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(177,'90 x 65 x 7',8.24,10.5,90.0,65.0,7.0,8.0,0.0,2.85,1.61,85.7,37.8,0.47,102.0,20.9,2.86,1.9,3.13,1.41,13.9,7.7,25.2,13.9,1.69,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(178,'90 x 65 x 8',9.34,11.9,90.0,65.0,8.0,8.0,0.0,2.89,1.65,96.3,42.3,0.47,115.0,23.5,2.84,1.89,3.11,1.4,15.8,8.7,28.5,15.7,2.5,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(179,'90 x 65 x 10',11.49,14.6,90.0,65.0,10.0,8.0,0.0,2.97,1.73,116.0,50.7,0.47,138.0,28.4,2.82,1.86,3.08,1.39,19.3,10.6,34.8,19.3,4.83,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(180,'100 x 50 x 6',6.92,8.81,100.0,50.0,6.0,9.0,0.0,3.51,1.06,91.9,15.9,0.26,97.5,10.3,3.23,1.34,3.33,1.08,14.2,4.0,24.8,7.4,1.03,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(181,'100 x 50 x 7',7.99,10.1,100.0,50.0,7.0,9.0,0.0,3.56,1.1,105.0,18.1,0.26,111.0,11.7,3.21,1.33,3.31,1.07,16.3,4.6,28.6,8.6,1.63,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(182,'100 x 50 x 8',9.05,11.5,100.0,50.0,8.0,9.0,0.0,3.6,1.14,118.0,20.2,0.25,125.0,13.1,3.2,1.32,3.29,1.07,18.5,5.2,32.2,9.8,2.42,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(183,'100 x 50 x 10',11.13,14.1,100.0,50.0,10.0,9.0,0.0,3.68,1.21,142.0,24.0,0.25,150.0,15.9,3.17,1.3,3.26,1.06,22.6,6.3,39.3,12.2,4.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(184,'100 x 65 x 7',8.85,11.2,100.0,65.0,7.0,10.0,0.0,3.25,1.53,115.0,38.9,0.4,131.0,22.8,3.2,1.86,3.41,1.42,17.1,7.8,30.7,14.1,1.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(185,'120 x 80 x 8',12.26,15.6,120.0,80.0,8.0,11.0,0.0,3.85,1.89,230.0,83.2,0.41,265.0,48.1,3.84,2.31,4.12,1.75,28.3,13.6,51.0,24.4,3.27,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(186,'120 x 80 x 10',15.12,19.2,120.0,80.0,10.0,11.0,0.0,3.94,1.96,280.0,100.0,0.41,322.0,58.3,3.81,2.28,4.09,1.74,34.8,16.6,62.6,30.1,6.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(187,'120 x 80 x 12',17.91,22.8,120.0,80.0,12.0,11.0,0.0,4.02,2.04,327.0,116.0,0.41,375.0,68.1,3.79,2.26,4.06,1.73,41.0,19.6,73.7,35.7,10.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(188,'125 x 75 x 12',17.91,22.8,125.0,75.0,12.0,11.0,0.0,4.32,1.85,358.0,97.5,0.34,396.0,59.8,3.97,2.07,4.17,1.62,43.9,17.3,78.1,31.8,10.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(189,'135 x 65 x 8',12.18,15.5,135.0,65.0,8.0,11.0,4.8,4.79,1.35,292.0,45.5,0.24,308.0,29.7,4.34,1.71,4.46,1.38,33.6,8.8,59.0,16.4,3.27,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(190,'135 x 65 x 10',15.04,19.1,135.0,65.0,10.0,11.0,4.8,4.88,1.43,357.0,55.0,0.24,376.0,36.1,4.32,1.69,4.43,1.37,41.4,10.8,72.5,20.5,6.33,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(191,'135 x 65 x 12',17.84,22.7,135.0,65.0,12.0,11.0,4.8,4.97,1.51,418.0,63.9,0.24,440.0,42.3,4.29,1.68,4.4,1.36,49.0,12.8,85.4,24.6,10.8,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(192,'150 x 75 x 9',15.39,19.6,150.0,75.0,9.0,11.0,4.8,5.28,1.58,457.0,78.8,0.26,485.0,50.7,4.83,2.01,4.98,1.61,47.1,13.3,82.8,24.5,5.24,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(193,'150 x 75 x 15',24.85,31.6,150.0,75.0,15.0,11.0,4.8,5.53,1.81,715.0,120.0,0.25,755.0,79.1,4.75,1.95,4.89,1.58,75.5,21.1,131.0,40.7,23.6,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(194,'150 x 90 x 10',18.22,23.2,150.0,90.0,10.0,12.0,4.8,5.0,2.04,536.0,147.0,0.35,594.0,89.1,4.81,2.52,5.06,1.96,53.6,21.2,96.2,38.4,7.66,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(195,'150 x 90 x 12',21.64,27.5,150.0,90.0,12.0,12.0,4.8,5.09,2.12,630.0,172.0,0.34,698.0,104.0,4.78,2.5,5.03,1.95,63.6,25.0,113.0,45.8,13.1,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(196,'150 x 90 x 15',26.66,33.9,150.0,90.0,15.0,12.0,4.8,5.21,2.24,764.0,206.0,0.34,843.0,126.0,4.74,2.47,4.98,1.93,78.0,30.6,139.0,56.7,25.3,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(197,'200 x 100 x 15',33.86,43.1,200.0,100.0,15.0,15.0,4.8,7.17,2.23,1770.0,303.0,0.25,1870.0,196.0,6.41,2.65,6.6,2.13,138.0,39.0,241.0,72.9,32.0,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(198,'200 x 150 x 15',39.75,50.6,200.0,150.0,15.0,15.0,4.8,6.22,3.75,2030.0,988.0,0.5,2490.0,530.0,6.34,4.42,7.02,3.24,147.0,87.8,268.0,157.0,37.6,'IS808_Rev',NULL); +INSERT INTO Angles VALUES(199,'200 x 150 x 18',47.21,60.1,200.0,150.0,18.0,15.0,4.8,6.34,3.86,2390.0,1150.0,0.5,2920.0,623.0,6.3,4.38,6.97,3.22,175.0,103.0,317.0,187.0,64.5,'IS808_Rev',NULL); +COMMIT; diff --git a/src/osdagbridge/core/data/ResourceFiles/Intg_osdag.sqlite b/src/osdagbridge/core/data/ResourceFiles/Intg_osdag.sqlite new file mode 100644 index 00000000..b03b1a16 Binary files /dev/null and b/src/osdagbridge/core/data/ResourceFiles/Intg_osdag.sqlite differ diff --git a/src/osdagbridge/core/data/ResourceFiles/precision.awk b/src/osdagbridge/core/data/ResourceFiles/precision.awk new file mode 100644 index 00000000..d44fd455 --- /dev/null +++ b/src/osdagbridge/core/data/ResourceFiles/precision.awk @@ -0,0 +1,81 @@ +#!/usr/bin/awk -f + +# awk script to reduce precision in output + +/^INSERT INTO / { + $0 = gensub(/(\.[0-9][1-9])00[0-9]*(,|\))/, "\\1\\2", "g"); + $0 = gensub(/(\.[0-9])000[0-9]*(,|\))/, "\\1\\2", "g"); + $0 = gensub(/(\.[0-9])099[0-9]*(,|\))/, "\\11\\2", "g"); + $0 = gensub(/(\.[0-9])199[0-9]*(,|\))/, "\\12\\2", "g"); + $0 = gensub(/(\.[0-9])299[0-9]*(,|\))/, "\\13\\2", "g"); + $0 = gensub(/(\.[0-9])399[0-9]*(,|\))/, "\\14\\2", "g"); + $0 = gensub(/(\.[0-9])499[0-9]*(,|\))/, "\\15\\2", "g"); + $0 = gensub(/(\.[0-9])599[0-9]*(,|\))/, "\\16\\2", "g"); + $0 = gensub(/(\.[0-9])699[0-9]*(,|\))/, "\\17\\2", "g"); + $0 = gensub(/(\.[0-9])799[0-9]*(,|\))/, "\\18\\2", "g"); + $0 = gensub(/(\.[0-9])899[0-9]*(,|\))/, "\\19\\2", "g"); + $0 = gensub(/(\.)0999[0-9]*(,|\))/, "\\11\\2", "g"); + $0 = gensub(/(\.)1999[0-9]*(,|\))/, "\\12\\2", "g"); + $0 = gensub(/(\.)2999[0-9]*(,|\))/, "\\13\\2", "g"); + $0 = gensub(/(\.)3999[0-9]*(,|\))/, "\\14\\2", "g"); + $0 = gensub(/(\.)4999[0-9]*(,|\))/, "\\15\\2", "g"); + $0 = gensub(/(\.)5999[0-9]*(,|\))/, "\\16\\2", "g"); + $0 = gensub(/(\.)6999[0-9]*(,|\))/, "\\17\\2", "g"); + $0 = gensub(/(\.)7999[0-9]*(,|\))/, "\\18\\2", "g"); + $0 = gensub(/(\.)8999[0-9]*(,|\))/, "\\19\\2", "g"); + $0 = gensub(/0(\.)9999[0-9]*(,|\))/, "1\\10\\2", "g"); + $0 = gensub(/1(\.)9999[0-9]*(,|\))/, "2\\10\\2", "g"); + $0 = gensub(/2(\.)9999[0-9]*(,|\))/, "3\\10\\2", "g"); + $0 = gensub(/3(\.)9999[0-9]*(,|\))/, "4\\10\\2", "g"); + $0 = gensub(/4(\.)9999[0-9]*(,|\))/, "5\\10\\2", "g"); + $0 = gensub(/5(\.)9999[0-9]*(,|\))/, "6\\10\\2", "g"); + $0 = gensub(/6(\.)9999[0-9]*(,|\))/, "7\\10\\2", "g"); + $0 = gensub(/7(\.)9999[0-9]*(,|\))/, "8\\10\\2", "g"); + $0 = gensub(/8(\.)9999[0-9]*(,|\))/, "9\\10\\2", "g"); + $0 = gensub(/\<9(\.)9999[0-9]*(,|\))/, "10\\10\\2", "g"); + $0 = gensub(/09(\.)9999[0-9]*(,|\))/, "10\\10\\2", "g"); + $0 = gensub(/19(\.)9999[0-9]*(,|\))/, "20\\10\\2", "g"); + $0 = gensub(/29(\.)9999[0-9]*(,|\))/, "30\\10\\2", "g"); + $0 = gensub(/39(\.)9999[0-9]*(,|\))/, "40\\10\\2", "g"); + $0 = gensub(/49(\.)9999[0-9]*(,|\))/, "50\\10\\2", "g"); + $0 = gensub(/59(\.)9999[0-9]*(,|\))/, "60\\10\\2", "g"); + $0 = gensub(/69(\.)9999[0-9]*(,|\))/, "70\\10\\2", "g"); + $0 = gensub(/79(\.)9999[0-9]*(,|\))/, "80\\10\\2", "g"); + $0 = gensub(/89(\.)9999[0-9]*(,|\))/, "90\\10\\2", "g"); + $0 = gensub(/\<99(\.)9999[0-9]*(,|\))/, "100\\10\\2", "g"); + $0 = gensub(/099(\.)9999[0-9]*(,|\))/, "100\\10\\2", "g"); + $0 = gensub(/199(\.)9999[0-9]*(,|\))/, "200\\10\\2", "g"); + $0 = gensub(/299(\.)9999[0-9]*(,|\))/, "300\\10\\2", "g"); + $0 = gensub(/399(\.)9999[0-9]*(,|\))/, "400\\10\\2", "g"); + $0 = gensub(/499(\.)9999[0-9]*(,|\))/, "500\\10\\2", "g"); + $0 = gensub(/599(\.)9999[0-9]*(,|\))/, "600\\10\\2", "g"); + $0 = gensub(/699(\.)9999[0-9]*(,|\))/, "700\\10\\2", "g"); + $0 = gensub(/799(\.)9999[0-9]*(,|\))/, "800\\10\\2", "g"); + $0 = gensub(/899(\.)9999[0-9]*(,|\))/, "900\\10\\2", "g"); + $0 = gensub(/\<999(\.)9999[0-9]*(,|\))/, "1000\\10\\2", "g"); + $0 = gensub(/0999(\.)9999[0-9]*(,|\))/, "1000\\10\\2", "g"); + $0 = gensub(/1999(\.)9999[0-9]*(,|\))/, "2000\\10\\2", "g"); + $0 = gensub(/2999(\.)9999[0-9]*(,|\))/, "3000\\10\\2", "g"); + $0 = gensub(/3999(\.)9999[0-9]*(,|\))/, "4000\\10\\2", "g"); + $0 = gensub(/4999(\.)9999[0-9]*(,|\))/, "5000\\10\\2", "g"); + $0 = gensub(/5999(\.)9999[0-9]*(,|\))/, "6000\\10\\2", "g"); + $0 = gensub(/6999(\.)9999[0-9]*(,|\))/, "7000\\10\\2", "g"); + $0 = gensub(/7999(\.)9999[0-9]*(,|\))/, "8000\\10\\2", "g"); + $0 = gensub(/8999(\.)9999[0-9]*(,|\))/, "9000\\10\\2", "g"); + $0 = gensub(/\<9999(\.)9999[0-9]*(,|\))/, "10000\\10\\2", "g"); + $0 = gensub(/09999(\.)9999[0-9]*(,|\))/, "10000\\10\\2", "g"); + $0 = gensub(/19999(\.)9999[0-9]*(,|\))/, "20000\\10\\2", "g"); + $0 = gensub(/29999(\.)9999[0-9]*(,|\))/, "30000\\10\\2", "g"); + $0 = gensub(/39999(\.)9999[0-9]*(,|\))/, "40000\\10\\2", "g"); + $0 = gensub(/49999(\.)9999[0-9]*(,|\))/, "50000\\10\\2", "g"); + $0 = gensub(/59999(\.)9999[0-9]*(,|\))/, "60000\\10\\2", "g"); + $0 = gensub(/69999(\.)9999[0-9]*(,|\))/, "70000\\10\\2", "g"); + $0 = gensub(/79999(\.)9999[0-9]*(,|\))/, "80000\\10\\2", "g"); + $0 = gensub(/89999(\.)9999[0-9]*(,|\))/, "90000\\10\\2", "g"); + print; + next; +} + +{ + print; +} \ No newline at end of file diff --git a/src/osdagbridge/core/utils/common.py b/src/osdagbridge/core/utils/common.py new file mode 100644 index 00000000..d7c5bfc7 --- /dev/null +++ b/src/osdagbridge/core/utils/common.py @@ -0,0 +1,244 @@ +# Constants for input types +TYPE_MODULE = "module" +TYPE_TITLE = "title" +TYPE_COMBOBOX = "combobox" +TYPE_COMBOBOX_CUSTOMIZED = "combobox_customized" +TYPE_TEXTBOX = "textbox" +TYPE_IMAGE = "image" + +# Keys for inputs +KEY_MODULE = "Module" +KEY_STRUCTURE_TYPE = "Structure Type" +KEY_PROJECT_LOCATION = "Project Location" +KEY_SPAN = "Span" +KEY_CARRIAGEWAY_WIDTH = "Carriageway Width" +KEY_INCLUDE_MEDIAN = "Include Median" +KEY_FOOTPATH = "Footpath" +KEY_SKEW_ANGLE = "Skew Angle" +KEY_GIRDER = "Girder" +KEY_CROSS_BRACING = "Cross Bracing" +KEY_END_DIAPHRAGM = "End Diaphragm" +KEY_DECK = "Deck" +KEY_DECK_CONCRETE_GRADE_BASIC = "Deck Concrete Grade" + +# Display names +KEY_DISP_FINPLATE = "Highway Bridge Design" +DISP_TITLE_STRUCTURE = "Type of Structure" +KEY_DISP_STRUCTURE_TYPE = "Structure Type" +DISP_TITLE_PROJECT = "Project Location" +KEY_DISP_PROJECT_LOCATION = "City in India*" +DISP_TITLE_GEOMETRIC = "Geometric Details" +KEY_DISP_SPAN = "Span (m)* [20-45]" +KEY_DISP_CARRIAGEWAY_WIDTH = "Carriageway Width (m)* [≥4.25]" +KEY_DISP_FOOTPATH = "Footpath" +KEY_DISP_SKEW_ANGLE = "Skew Angle (degrees) [±15]" +DISP_TITLE_MATERIAL = "Material Inputs" +KEY_DISP_GIRDER = "Girder" +KEY_DISP_CROSS_BRACING = "Cross Bracing" +KEY_DISP_END_DIAPHRAGM = "End Diaphragm" +KEY_DISP_DECK = "Deck" +KEY_DISP_DECK_CONCRETE_GRADE = "Deck Concrete Grade [M25+]" + +# Sample values +# Type of Structure: Defines the application of the steel girder bridge +# Currently only covers highway bridge +VALUES_STRUCTURE_TYPE = ["Highway Bridge", "Other"] + +# Project Location: Cities in India for load calculations +# Organized by regions for easier navigation +VALUES_PROJECT_LOCATION = [ + "Delhi", "Mumbai", "Bangalore", "Kolkata", "Chennai", "Hyderabad", + "Ahmedabad", "Pune", "Surat", "Jaipur", "Lucknow", "Kanpur", + "Nagpur", "Indore", "Thane", "Bhopal", "Visakhapatnam", "Pimpri-Chinchwad", + "Patna", "Vadodara", "Ghaziabad", "Ludhiana", "Agra", "Nashik", + "Faridabad", "Meerut", "Rajkot", "Kalyan-Dombivali", "Vasai-Virar", "Varanasi", + "Srinagar", "Aurangabad", "Dhanbad", "Amritsar", "Navi Mumbai", "Allahabad", + "Ranchi", "Howrah", "Coimbatore", "Jabalpur", "Gwalior", "Vijayawada", + "Jodhpur", "Madurai", "Raipur", "Kota", "Chandigarh", "Guwahati", + "Custom" # Allow custom location entry +] + +# Footpath: Single sided or none or both +# Default: None +# Note: IRC 5 Clause 101.41 requires safety kerb when footpath is not present +VALUES_FOOTPATH = ["None", "Single Sided", "Both"] + +VALUES_MATERIAL = [ + "E 250A", "E 250BR", "E 250B0", "E 250C", + "E 275A", "E 275BR", "E 275B0", "E 275C", + "E 300A", "E 300BR", "E 300B0", "E 300C", + "E 350A", "E 350BR", "E 350B0", "E 350C", + "E 410A", "E 410BR", "E 410B0", "E 410C", + "E 450A", "E 450BR", + "E 550A", "E 550BR", + "E 600A", "E 600BR", + "E 650A", "E 650BR" +] + +# Validation limits +# Span: Between 20 to 45 meters +SPAN_MIN = 20.0 +SPAN_MAX = 45.0 + +# Carriageway Width limits per IRC 5 Clause 104.3.1 +CARRIAGEWAY_WIDTH_MIN = 4.25 # No median present +CARRIAGEWAY_WIDTH_MIN_WITH_MEDIAN = 7.5 # Each carriageway when median provided +CARRIAGEWAY_WIDTH_MAX_LIMIT = 23.6 # Current software cap (subject to change) + +# Skew Angle: IRC 24 (2010) requires detailed analysis when skew angle exceeds ±15 degrees +# Default: 0 degrees +SKEW_ANGLE_MIN = -15.0 +SKEW_ANGLE_MAX = 15.0 +SKEW_ANGLE_DEFAULT = 0.0 + +# ===== Additional Inputs Constants ===== + +# Typical Section Details Keys +KEY_GIRDER_SPACING = "Girder Spacing" +KEY_DECK_OVERHANG = "Deck Overhang Width" +KEY_NO_OF_GIRDERS = "No. of Girders" +KEY_DECK_THICKNESS = "Deck Thickness" +KEY_DECK_CONCRETE_GRADE = "Deck Concrete Grade" +KEY_DECK_REINF_MATERIAL = "Deck Reinforcement Material" +KEY_DECK_REINF_SIZE = "Deck Reinforcement Size" +KEY_DECK_REINF_SPACING_LONG = "Deck Reinforcement Spacing Longitudinal" +KEY_DECK_REINF_SPACING_TRANS = "Deck Reinforcement Spacing Transverse" +KEY_FOOTPATH_WIDTH = "Footpath Width" +KEY_FOOTPATH_THICKNESS = "Footpath Thickness" +KEY_RAILING_PRESENT = "Railing Present" +KEY_RAILING_WIDTH = "Railing Width" +KEY_RAILING_HEIGHT = "Railing Height" +KEY_SAFETY_KERB_PRESENT = "Safety Kerb Present" +KEY_SAFETY_KERB_WIDTH = "Safety Kerb Width" +KEY_SAFETY_KERB_THICKNESS = "Safety Kerb Thickness" +KEY_CRASH_BARRIER_PRESENT = "Crash Barrier Present" +KEY_CRASH_BARRIER_TYPE = "Crash Barrier Type" +KEY_CRASH_BARRIER_DENSITY = "Crash Barrier Material Density" +KEY_CRASH_BARRIER_WIDTH = "Crash Barrier Width" +KEY_CRASH_BARRIER_AREA = "Crash Barrier Area" + +# Section Properties Keys +KEY_GIRDER_TYPE = "Girder Type" +KEY_GIRDER_IS_SECTION = "Girder IS Section" +KEY_GIRDER_SYMMETRY = "Girder Symmetry" +KEY_GIRDER_TOP_FLANGE_WIDTH = "Girder Top Flange Width" +KEY_GIRDER_TOP_FLANGE_THICKNESS = "Girder Top Flange Thickness" +KEY_GIRDER_BOTTOM_FLANGE_WIDTH = "Girder Bottom Flange Width" +KEY_GIRDER_BOTTOM_FLANGE_THICKNESS = "Girder Bottom Flange Thickness" +KEY_GIRDER_DEPTH = "Girder Depth" +KEY_GIRDER_WEB_THICKNESS = "Girder Web Thickness" +KEY_GIRDER_TORSIONAL_RESTRAINT = "Torsional Restraint" +KEY_GIRDER_WARPING_RESTRAINT = "Warping Restraint" +KEY_GIRDER_WEB_TYPE = "Web Type" + +KEY_STIFFENER_DESIGN_METHOD = "Stiffener Design Method" +KEY_STIFFENER_PLATE_THICKNESS = "Stiffener Plate Thickness" +KEY_STIFFENER_SPACING = "Stiffener Spacing" +KEY_LONGITUDINAL_STIFFENER = "Longitudinal Stiffener" +KEY_LONGITUDINAL_STIFFENER_THICKNESS = "Longitudinal Stiffener Thickness" + +KEY_CROSS_BRACING_TYPE = "Cross Bracing Type" +KEY_CROSS_BRACING_SECTION = "Cross Bracing Section" +KEY_BRACKET_SECTION = "Bracket Section" +KEY_CROSS_BRACING_SPACING = "Cross Bracing Spacing" + +KEY_END_DIAPHRAGM_TYPE = "End Diaphragm Type" +KEY_END_DIAPHRAGM_SECTION = "End Diaphragm Section" +KEY_END_DIAPHRAGM_SPACING = "End Diaphragm Spacing" + +# Dead Load Keys +KEY_SELF_WEIGHT = "Self Weight" +KEY_SELF_WEIGHT_FACTOR = "Self Weight Factor" +KEY_WEARING_COAT_MATERIAL = "Wearing Coat Material" +KEY_WEARING_COAT_DENSITY = "Wearing Coat Density" +KEY_WEARING_COAT_THICKNESS = "Wearing Coat Thickness" +KEY_RAILING_LOAD_COUNT = "No. of Railings" +KEY_RAILING_LOAD = "Railing Load" +KEY_RAILING_LOAD_LOCATION = "Railing Load Location" +KEY_CRASH_BARRIER_LOAD_COUNT = "No. of Crash Barriers" +KEY_CRASH_BARRIER_LOAD = "Crash Barrier Load" +KEY_CRASH_BARRIER_LOAD_LOCATION = "Crash Barrier Load Location" + +# Live Load Keys +KEY_IRC_CLASS_A = "IRC Class A" +KEY_IRC_CLASS_70R = "IRC Class 70R" +KEY_IRC_CLASS_AA = "IRC Class AA" +KEY_IRC_CLASS_SV = "IRC Class SV" +KEY_CUSTOM_VEHICLE = "Custom Vehicle" +KEY_CUSTOM_AXLE_TYPE = "Custom Axle Type" +KEY_CUSTOM_NO_AXLES = "Custom Number of Axles" +KEY_CUSTOM_AXLE_LOAD = "Custom Axle Load" +KEY_CUSTOM_AXLE_SPACING = "Custom Axle Spacing" +KEY_CUSTOM_VEHICLE_SPACING = "Custom Vehicle Spacing" +KEY_CUSTOM_ECCENTRICITY = "Custom Eccentricity" +KEY_FOOTPATH_PRESSURE = "Footpath Pressure" +KEY_FOOTPATH_PRESSURE_VALUE = "Footpath Pressure Value" + +# Support Condition Keys +KEY_LEFT_SUPPORT = "Left Support" +KEY_RIGHT_SUPPORT = "Right Support" +KEY_BEARING_LENGTH = "Bearing Length" + +# Value Lists for Additional Inputs +VALUES_YES_NO = ["No", "Yes"] +VALUES_DECK_CONCRETE_GRADE = [ + "M 25", "M 30", "M 35", "M 40", "M 45", "M 50", + "M 55", "M 60", "M 65", "M 70", "M 75", "M 80", + "M 85", "M 90" +] +VALUES_REINF_MATERIAL = ["Fe 415", "Fe 500", "Fe 550"] +VALUES_REINF_SIZE = ["8", "10", "12", "16", "20", "25", "32"] +VALUES_CRASH_BARRIER_TYPE = [ + "IRC 5 - RCC Crash Barrier", + "IRC 5 - Steel Crash Barrier", + "IRC 5 - Metal Beam", + "Custom" +] +VALUES_MEDIAN_TYPE = [ + "IRC 5 - Raised Kerb", + "IRC 5 - Flush Median", + "Custom" +] +VALUES_GIRDER_TYPE = ["Welded", "Rolled"] +VALUES_GIRDER_SYMMETRY = ["Girder Symmetric", "Girder Unsymmetric"] +VALUES_GIRDER_DESIGN_MODE = ["Optimized", "Customized"] +VALUES_GIRDER_SPAN_MODE = ["Full Length", "Custom"] +VALUES_PROFILE_SCOPE = ["All", "Custom"] +VALUES_OPTIMIZATION_MODE = ["Optimized", "Customized", "All"] +VALUES_TORSIONAL_RESTRAINT = ["Fully Restrained", "Partially Restrained - Support Connect", "Partially Restrained - Bearing Support"] +VALUES_WARPING_RESTRAINT = ["Both Flange Restraint", "No Restraint"] +VALUES_WEB_TYPE = ["Thin Web with ITS", "Thick Web with ITS"] +VALUES_STIFFENER_DESIGN = ["Simple Post", "Tension Field"] +VALUES_CROSS_BRACING_TYPE = ["K-bracing", "K-bracing with top bracket", "X-bracing", "X-bracing with bottom bracket", "X-bracing with top and bottom brackets"] +VALUES_END_DIAPHRAGM_TYPE = ["Cross Bracing", "Rolled Beam", "Welded Beam"] +VALUES_WEARING_COAT_MATERIAL = ["Concrete", "Bituminous", "Other"] +VALUES_RAILING_TYPE = [ + "IRC 5 - RCC Railing", + "IRC 5 - Steel Railing", + "Custom" +] +VALUES_CUSTOM_AXLE_TYPE = ["Single", "Bogie"] +VALUES_FOOTPATH_PRESSURE_MODE = ["Automatic", "User-defined"] +VALUES_SUPPORT_TYPE = ["Fixed", "Pinned"] + +# Default values +DEFAULT_SELF_WEIGHT_FACTOR = 1.0 +DEFAULT_CONCRETE_DENSITY = 25.0 # kN/m³ +DEFAULT_STEEL_DENSITY = 78.5 # kN/m³ +DEFAULT_BEARING_LENGTH = 0.0 # mm + +# Typical Section Details Validation Constants (IRC 5) +MIN_FOOTPATH_WIDTH = 1.5 # meters (IRC 5 Clause 104.3.6) +MIN_RAILING_HEIGHT = 1.0 # meters (IRC 5 Clauses 109.7.2.3 & 109.7.2.4) +MIN_SAFETY_KERB_WIDTH = 0.75 # meters (IRC 5 Clause 101.41) +DEFAULT_GIRDER_SPACING = 2.5 # meters (preliminary design assumption) +DEFAULT_DECK_OVERHANG = 1.0 # meters (preliminary design assumption) +DEFAULT_CRASH_BARRIER_WIDTH = 0.5 # meters (typical) +DEFAULT_RAILING_WIDTH = 0.15 # meters (typical) + +def connectdb(table_name, popup=None): + """Mock database connection - returns sample data""" + if table_name == "Material": + return VALUES_MATERIAL + return [] + diff --git a/src/osdagbridge/desktop/__init__.py b/src/osdagbridge/desktop/__init__.py deleted file mode 100644 index 8523eba9..00000000 --- a/src/osdagbridge/desktop/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Desktop adapter package.""" diff --git a/src/osdagbridge/desktop/__main__.py b/src/osdagbridge/desktop/__main__.py new file mode 100644 index 00000000..1149e7ff --- /dev/null +++ b/src/osdagbridge/desktop/__main__.py @@ -0,0 +1,37 @@ +import sys +from PySide6.QtWidgets import QApplication +from PySide6.QtCore import QFile, QTextStream +from osdagbridge.desktop.resources import resources_rc + +# Import template_page +from osdagbridge.desktop.ui.template_page import CustomWindow +from osdagbridge.core.bridge_types.plate_girder.ui_fields import FrontendData + +def load_stylesheet(): + """Load the global QSS stylesheet from resources.""" + file = QFile(":/themes/lightstyle.qss") + if file.open(QFile.ReadOnly | QFile.Text): + stream = QTextStream(file) + stylesheet = stream.readAll() + file.close() + return stylesheet + return "" + +def main(): + # Create the Qt application instance + app = QApplication(sys.argv) + + # Load and apply the global stylesheet + stylesheet = load_stylesheet() + if stylesheet: + app.setStyleSheet(stylesheet) + + window = CustomWindow("Osdag Bridge", FrontendData) + window.showMaximized() + window.show() + + # Execute the event loop + sys.exit(app.exec()) + +if __name__ == "__main__": + main() diff --git a/src/osdagbridge/desktop/main.py b/src/osdagbridge/desktop/main.py deleted file mode 100644 index 418a2a6f..00000000 --- a/src/osdagbridge/desktop/main.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Desktop bootstrap (PySide6 stub).""" -def start(): - print("Starting desktop UI (stub)") diff --git a/src/osdagbridge/desktop/resources/__init__.py b/src/osdagbridge/desktop/resources/__init__.py new file mode 100644 index 00000000..068deaab --- /dev/null +++ b/src/osdagbridge/desktop/resources/__init__.py @@ -0,0 +1,3 @@ +"""Resource package exposing compiled Qt assets.""" + +from . import resources_rc # noqa: F401 re-export for legacy imports diff --git a/src/osdagbridge/desktop/resources/resources.qrc b/src/osdagbridge/desktop/resources/resources.qrc new file mode 100644 index 00000000..a876dcf2 --- /dev/null +++ b/src/osdagbridge/desktop/resources/resources.qrc @@ -0,0 +1,36 @@ + + + + + + + + + vectors/arrow_down_light.svg + vectors/arrow_down_dark.svg + vectors/arrow_up_light.svg + vectors/arrow_up_dark.svg + + themes/lightstyle.qss + + vectors/design.svg + vectors/save.svg + vectors/checked.svg + vectors/design_report.svg + vectors/lock_open.svg + vectors/lock_close.svg + vectors/Osdag_logo.svg + + vectors/inputs_label_light.svg + vectors/input_dock_active_light.svg + vectors/input_dock_inactive_light.svg + + vectors/logs_dock_active_light.svg + vectors/logs_dock_inactive_light.svg + + vectors/output_dock_active_light.svg + vectors/output_dock_inactive_light.svg + vectors/outputs_label_light.svg + + + diff --git a/src/osdagbridge/desktop/resources/resources_rc.py b/src/osdagbridge/desktop/resources/resources_rc.py new file mode 100644 index 00000000..79a25e66 --- /dev/null +++ b/src/osdagbridge/desktop/resources/resources_rc.py @@ -0,0 +1,1471 @@ +# Resource object code (Python 3) +# Created by: object code +# Created by: The Resource Compiler for Qt version 6.9.2 +# WARNING! All changes made in this file will be lost! + +from PySide6 import QtCore + +qt_resource_data = b"\ +\x00\x00\x04\xe7\ +\x00\ +\x00\x15\xe8x\xda\xd5X]O\xdb<\x14\xbeG\xe2?\ +X\xea\xc5>\xb4\xae-\x85\x8e\x05\xbd\x17\xfd\x82!\x15\ +\x18\xb4\xdb\xc4n\x90\x93\xb8\xad\x85\x1bg\x8eC\xe1\x9d\ +\xf8\xef\xef\xb1\x9b\xef&n`\xef\xcdb\x0du\xb6s\ +\xce\xe3\xc7\x8f\xcf9N\xeb=\xfa\xe7E\xcf\xfe\x1eB\ +\xe8j:\xea\x9f\xa1\xb3o\xe7h:\xbb\x9d\x8c\xa7_\ +\xc6\xe3\x19j\xa2\xab\x9b\xb3\xfe\xe5\xf9\xcf\xf1\x08\x0dn\ +\xd1\xf4\xebxx~z><\x9f\xdd\xeaw^\xe6\x06\ +\xbdo\xed\xef\xed\xef\xb5^\x05\xaf\xf3\x11\x9dM\xae\x06\ +\xfdI\x04\x0f\xbd\x9d\x10\x1cH4\xf5\x89C\xe7\xd4y\ +\xf7Z@\xd7\x17\x98z?\xa8\xe7\xf25\xfa\xad\x8d \ +\x1b;\xf7\x0b\xc1C\xcfm:\x9cqa\xa1\xc6\xfcP\ +\xb5\x93h\x9c\x0b\x97@o\xc7\x7fD\x01g\xd4E\x8d\ +\xcfm<\xeft\xa3\xf1\x15\x16\x0b\xeaY\xa8\xed?F\ +=>v]\xea-\xe2\xaeg\xc5\xc3\xf5\x8cs6\xa3\ +\xbe\xc1\xeb\xa9~\x22\x1bqg[?&(\xfd\xd3\x04\ +J\xe2\xf8\x00&\x1c$x\xe6\xdc\x93\xcd\x80\xfeK\xe0\ +\xcd\xb4wc\xac)\xb0K\xc3 \x0b\xff\x97/\xb8O\ +\x84|jbF\x17\xde\x8ax\xd2B}\xf5\xf3\xfb\x10\ +~\x13\xb1Y\xd3\xf5\xd4gT\xc2\x7f-k\x89=\x97\ +\x11\xc3\xd2Fm\xd5b.@\x13g\x8c\xdb\x98\xa1\xe1\ +\x928\xf76\x7fDS\xf9\x04\x06\xf4\x0e\xe9\xbe\x01\xf4\ +\xfd\xdeF\x9f\x82\x8c-w\xbb\xf1\xe2\x03\x1f;z\xf1\ +\xbd\x98\xf5\xc4\x94e\xc1\x8eS\x07K.b\xabk\xea\ +\xca%X\xec%\x16\x97\x84.\x962\xd7U\xc2wW\ +?\xe5\x14v\xd3\x17K4\xa5\x9fj`\xd6\x92?\x90\ +\x04^\x89\xe7#\xfd\x18\x0c8\xaa\x8f\xb8&]\xc7\x18\ +\xea,\x8e\xae\xf0\x028\x0f\x05{k\xb5\x1e\x88\x03.\ +\x82V\xe4\xe3c\xf0\xb0x\x97H\xfb\x82x\xe1\x00\x8b\ +\x86$+\x9faI\xee|x\xf3\x0et\x13\xde\xd9X\ +\x98\x14\x7f\xa8\x9aI\xf1\xdbGi\x877 \x04\x06b\ +\x9f\xc9\xebG\xb0\xc8\x8czR,\x16\x92\x02{\xa0\x1d\ +\x01\xd26\x9d\x8c\xba\xae\xad\x800 \xabl\x1f\xb2g\ +\xbc\xb69_\x90 \xa8\xb06>V\xad\x965\xa4\xc7\ +\xebF\x9f\x12m$G\xb8\x84\xa1CC\xe8\xab\x85\xab\ +z\xd7L\xe2\xc8F\x86\xce+\xfc\x19\xb6*\xa1e\xdc\ +;m\x17h)\x9c\xf7\xfa>\x03\x022\xcb\x06\xa1$\ +\xe4\x94\x0a\xb3\x01\x9e\xa1\xe5\xd2L\x93\x91\xb9\xb42\xb1\ +=\xea\x16\x1bC[\xfd\x92\xfb\xd9\xd0\x1e\xf5\xda\x5cJ\ +\xbez\xf9&i/M,D\x9a=\xa38z\xbc\x15\ +F\x8f\xd3\xdc\x07\xf1~\x04)\x05r\xae\x87\x94I\x14\ +\xa4\xd1\xbe\x5c\x95\x9bXU3\xebeephN\xc2\ +\x06\xad\x1d\xab\x08\xd13\xe4\x97\x18\x86\xc7=RH\xfd\ +\x9dR\x17\xe6H\x90[B&@\x97K\xed \xc7\xe6\ ++*\xaa.TT\xe3\xcb\xf1\x0d\x94T\x83o\xb3\xd9\ +\xd5eRY\x0dp@\xd0\x84<\x10\xf6\xfa\xaa\xeak\ +\x18,\x07!\x88\xca\xab>J\xeb%\x90\x92_\xaf\xcd\ +`Vv\x17\xd7\x91xl\xce\xdc\x13T\xca\xc4\x91!\ +;g\xed\xe5C\x7f\xaa\x0bI\x1e\xe5\xa6\xb0\xb1\x90\x93\ +)gr\xab($\xe3\xed\xb0\x90\xdb\xbd]\x02-\x10\ +\xb0\xe5\xac\x10\xe2K\xc81\xb3YM\xc4\xc6\xd5\x0f\xea\ +.\x88l\x0c\xc3\x00N\xfd\x8cJF\x06*-\xa3\xdd\ +\xf5\xaf\x0a\x0d\x13l\x13\xd6\xd0\xaf\xe9\x9f\x05\x98\xc6|\ +m\xce\xb5\xa9\xf5\x09_\xf0\x9cqs\x82.\xadg\xb6\ +\xc3@Zxo\x88n\x5cP\x8f\xae`\xc6.\xa9V\ +{,-\xc7\xdb\xbbk\xea,\xb8\x9ey\xfa\x0e\xd4;\ +\xa59\xef\xa8V\xc3Pee\x91\x98\xc2=\xd5JM\ +\xe1\xc7\x1b\x02r\x12\x7f\x1b\x97\x05\xdc\x7f\xc2f\xd1\xd4\ +\x9f\xf09d<\xf8\xcb\xa8\xcc@\xde\xc9\x22\xf9t\xe8\ +t\x9d\xaa\xd3k4\xbd\x9bU\xa7\xdd\xfd|`G\xf1\ +$\x8au\x03]\xe1L\xa8G\xea\x04\xf1g\x95U+\ +\x12\x1c\x84\xa6\xa09\xe2\xce\xbd!\x09\xea\x1c\x18yf\ +0\xff\xce\x85\xf9\xe8\xba\x22\xa2\xa5%\xf7\x81j\xb5\xae\ +?\xdd\xfc\x96\xe5\xf2d\xd5%\xff\xb9\x14\xd4\x0c\xf2\xdf\ +\xd8\xa5\xd2\x84\xebX\xb5\x9aW\x01\xedw\x8eW\x94=\ +Y\xe8\xcd\x90\x87\x82\x82\x14.\xc9\xfa\xcd\x07\xb4\xe2\x1e\ +W\xd7rb\xfc\x10Q\xa7\xdc/_\xcb\xd4\x11\x9c1\ +Hf\x16\xc8O\xc25\x98\x95_\x93\xda\xaa\x9d \xa8\ +\x9c&\x8a7\xb4\x10\xe4\x09\xc0\x08$\x97\x04\x05\xda\x88\ +\xaar\xe1|\x81U\xb5\x99\xa5\x95m\xe6CO\xf2\xaf\ +[uhL[\x90\xc2\x8e\xbe\x9c\x98\xe1\xf7\xdb\xaai\ +\xf8\x17\x04\xac\xaf\xaa\xf0G\x9fa\xe2\x05\xac\xa0\xd2\x8f\ +\xab\xf1n\xfb\xff\x05Zu\xe2\x01\xee\xa7\xb6j\x1a\xee\ +\x08\x8b{\x98\xa5\xe1B`\xdb\xbc\x13\xe3\xce\xa0\xdd\xe9\ +\x1d\x14\xd2dp\x98\x13\xff\x1fr\xc3Ah\xe7\x87\x8b\ +\x17,\xb5z\x05\xe8\x0buI\xa0\xbd\x87~K\xdfG\ +\xf4e&\xa8\x8fB\xdd\x8b\x0c(r\xc3e\xf4\xe8\xdb\ +C\x1e\x0a\x04t\x8cl\x22\xd7\x84x1+\xf0\xb7\x00\ +\xed??\x04\x81\x7f\ +\x00\x00\x00\xb2\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x222\ +4px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2224px\x22 fill=\ +\x22#90af13\x22>\ +\x00\x00\x02-\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x0e;\ +<\ +svg width=\x22149\x22 \ +height=\x22141\x22 vie\ +wBox=\x220 0 149 14\ +1\x22 fill=\x22none\x22 x\ +mlns=\x22http://www\ +.w3.org/2000/svg\ +\x22>\x0d\x0a\x0d\x0a<\ +path d=\x22M130.212\ + 67.3074L115.887\ + 51.8725L130.121\ + 36.1514L130.212\ + 67.3074Z\x22 fill=\ +\x22black\x22/>\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x02\xfe\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x02\x07\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x021\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +\ +\x00\x00\x01\xa4\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x02\xd3\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +\x00\x00\x05O\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x08+\ +<\ +svg width=\x2236\x22 h\ +eight=\x22922\x22 view\ +Box=\x220 0 36 922\x22\ + fill=\x22none\x22 xml\ +ns=\x22http://www.w\ +3.org/2000/svg\x22>\ +\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x02\xde\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x021\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\ +\x00\x00\x0aV\ +<\ +svg width=\x2236\x22 h\ +eight=\x22918\x22 view\ +Box=\x220 0 36 918\x22\ + fill=\x22none\x22 xml\ +ns=\x22http://www.w\ +3.org/2000/svg\x22>\ +\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x05O\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x02\xbb\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +\x00\x00\x02/\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x01\x9d\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x01\xa2\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x025\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +" + +qt_resource_name = b"\ +\x00\x07\ +\x0c\xba\xb6s\ +\x00v\ +\x00e\x00c\x00t\x00o\x00r\x00s\ +\x00\x06\ +\x07\xae\xc3\xc3\ +\x00t\ +\x00h\x00e\x00m\x00e\x00s\ +\x00\x0e\ +\x03\x9b1c\ +\x00l\ +\x00i\x00g\x00h\x00t\x00s\x00t\x00y\x00l\x00e\x00.\x00q\x00s\x00s\ +\x00\x0b\ +\x01d\x8d\x87\ +\x00c\ +\x00h\x00e\x00c\x00k\x00e\x00d\x00.\x00s\x00v\x00g\ +\x00\x1b\ +\x0aa\xaa'\ +\x00i\ +\x00n\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00a\x00c\x00t\x00i\x00v\x00e\ +\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x0e\ +\x06\xb1\x9b\x07\ +\x00O\ +\x00s\x00d\x00a\x00g\x00_\x00l\x00o\x00g\x00o\x00.\x00s\x00v\x00g\ +\x00\x0e\ +\x0d\xd6\xeag\ +\x00l\ +\x00o\x00c\x00k\x00_\x00c\x00l\x00o\x00s\x00e\x00.\x00s\x00v\x00g\ +\x00\x1a\ +\x0b}\x5cG\ +\x00l\ +\x00o\x00g\x00s\x00_\x00d\x00o\x00c\x00k\x00_\x00a\x00c\x00t\x00i\x00v\x00e\x00_\ +\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x13\ +\x0cPg\xa7\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00d\x00o\x00w\x00n\x00_\x00d\x00a\x00r\x00k\x00.\x00s\ +\x00v\x00g\ +\x00\x1e\ +\x08a\xb9\xc7\ +\x00o\ +\x00u\x00t\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00i\x00n\x00a\x00c\x00t\ +\x00i\x00v\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x0a\ +\x0f\xec\x03\xe7\ +\x00d\ +\x00e\x00s\x00i\x00g\x00n\x00.\x00s\x00v\x00g\ +\x00\x12\ +\x0aDDG\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00u\x00p\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\ +\x00g\ +\x00\x16\ +\x0e\x16='\ +\x00i\ +\x00n\x00p\x00u\x00t\x00s\x00_\x00l\x00a\x00b\x00e\x00l\x00_\x00l\x00i\x00g\x00h\ +\x00t\x00.\x00s\x00v\x00g\ +\x00\x0d\ +\x005w\xc7\ +\x00l\ +\x00o\x00c\x00k\x00_\x00o\x00p\x00e\x00n\x00.\x00s\x00v\x00g\ +\x00\x14\ +\x01\xd3}\xa7\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00d\x00o\x00w\x00n\x00_\x00l\x00i\x00g\x00h\x00t\x00.\ +\x00s\x00v\x00g\ +\x00\x17\ +\x0d\xa0\xcd'\ +\x00o\ +\x00u\x00t\x00p\x00u\x00t\x00s\x00_\x00l\x00a\x00b\x00e\x00l\x00_\x00l\x00i\x00g\ +\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x11\ +\x03\xf9t'\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00u\x00p\x00_\x00d\x00a\x00r\x00k\x00.\x00s\x00v\x00g\ +\ +\x00\x11\ +\x08\xb1e\xc7\ +\x00d\ +\x00e\x00s\x00i\x00g\x00n\x00_\x00r\x00e\x00p\x00o\x00r\x00t\x00.\x00s\x00v\x00g\ +\ +\x00\x1c\ +\x0ap\xe4'\ +\x00o\ +\x00u\x00t\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00a\x00c\x00t\x00i\x00v\ +\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x1c\ +\x01\xd8[\xc7\ +\x00l\ +\x00o\x00g\x00s\x00_\x00d\x00o\x00c\x00k\x00_\x00i\x00n\x00a\x00c\x00t\x00i\x00v\ +\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x1d\ +\x0e\xaf\xb9\xe7\ +\x00i\ +\x00n\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00i\x00n\x00a\x00c\x00t\x00i\ +\x00v\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x08\ +\x08\xc8U\xe7\ +\x00s\ +\x00a\x00v\x00e\x00.\x00s\x00v\x00g\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x16\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x13\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00/T\ +\x00\x00\x01\x9b\x13E\x17;\ +\x00\x00\x00H\x00\x00\x00\x00\x00\x01\x00\x00\x04\xeb\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x02\x22\x00\x00\x00\x00\x00\x01\x00\x0026\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x03\x12\x00\x00\x00\x00\x00\x01\x00\x00I\x0a\ +\x00\x00\x01\x9a\xfc\x9f}A\ +\x00\x00\x02\x84\x00\x00\x00\x00\x00\x01\x00\x00>\xc5\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x07\xd2\ +\x00\x00\x01\x9b\x13\xd0_\xa8\ +\x00\x00\x01J\x00\x00\x00\x00\x00\x01\x00\x00\x1dS\ +\x00\x00\x01\x9a\xfc\x9f}M\ +\x00\x00\x02\xac\x00\x00\x00\x00\x00\x01\x00\x00D\x18\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x03\x90\x00\x00\x00\x00\x00\x01\x00\x00LQ\ +\x00\x00\x01\x9b\x13E\x17;\ +\x00\x00\x01\xa6\x00\x00\x00\x00\x00\x01\x00\x00!\xd2\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x00d\x00\x00\x00\x00\x00\x01\x00\x00\x05\xa1\ +\x00\x00\x01\x9a\xfc\x9f};\ +\x00\x00\x02\xd4\x00\x00\x00\x00\x00\x01\x00\x00F\xd7\ +\x00\x00\x01\x9a\xfc\x9f}K\ +\x00\x00\x00\xe4\x00\x00\x00\x00\x00\x01\x00\x00\x19\x13\ +\x00\x00\x01\x9a\xfc\x9f}A\ +\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x1e\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x02P\x00\x00\x00\x00\x00\x01\x00\x004k\ +\x00\x00\x01\x9b\x07\x002e\ +\x00\x00\x00\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x16\x11\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x01\xd0\x00\x00\x00\x00\x00\x01\x00\x00'%\ +\x00\x00\x01\x9b\x07\x002a\ +\x00\x00\x03P\x00\x00\x00\x00\x00\x01\x00\x00J\xab\ +\x00\x00\x01\x9a\xfc\x9f}<\ +\x00\x00\x01\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x1e\xfb\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x00&\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x9b\x13\xd50\xdc\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/src/osdagbridge/desktop/resources/themes/darkstyle.qss b/src/osdagbridge/desktop/resources/themes/darkstyle.qss new file mode 100644 index 00000000..f9c6f9ac --- /dev/null +++ b/src/osdagbridge/desktop/resources/themes/darkstyle.qss @@ -0,0 +1,32 @@ +/* ============================================== + OSDAG GUI STYLESHEET - ORGANIZED BY SPECIFICITY + ============================================== */ + +/* ============================================== + 1. GLOBAL STYLES (Least Specific) + ============================================== */ +* { + font-family: "Ubuntu Sans"; +} + +QMainWindow { + background-color: #282828; + border: 1px solid #6B7D20; + margin: 0px; + padding: 0px; +} + +QTabWidget { + background-color: #333333; + border: 0px; +} + +QToolTip { + background-color: #2B2B2B; + color: #D0D0D0; + border: 1px solid #6B7D20; + padding: 2px 2px; + font-size: 12px; + border-radius: 0px; + qproperty-alignment: AlignVCenter; +} \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/themes/lightstyle.qss b/src/osdagbridge/desktop/resources/themes/lightstyle.qss new file mode 100644 index 00000000..452eeeb6 --- /dev/null +++ b/src/osdagbridge/desktop/resources/themes/lightstyle.qss @@ -0,0 +1,243 @@ +/* ============================================== + OSDAG GUI STYLESHEET - ORGANIZED BY SPECIFICITY + ============================================== */ + +/* ============================================== + 1. GLOBAL STYLES (Least Specific) + ============================================== */ +QMainWindow { + background-color: #f4f4f4; + border: 1px solid #90af13; + margin: 0px; + padding: 0px; +} + +QToolTip { + background-color: #FFFFFF; + color: #000000; + border: 1px solid #90AF13; + padding: 2px 2px; + font-size: 12px; + border-radius: 0px; + qproperty-alignment: AlignVCenter; +} +QSplitter::handle { + background-color: #D0D0D0; +} + +/* Global Checkbox Style */ +QCheckBox { + font-size: 10px; + color: #333; + spacing: 6px; +} +QCheckBox::indicator { + width: 16px; + height: 16px; + border: 1px solid #333333; + border-radius: 3px; + background-color: #ffffff; +} +QCheckBox::indicator:hover { + border: 1px solid #555555; +} +QCheckBox::indicator:checked { + background-color: #ffffff; + border: 1px solid #333333; + image: url(:/vectors/checked.svg); +} + +QMenuBar#template_page_menu_bar { + background-color: #F4F4F4; + color: #000000; + padding: 0px; +} +QMenuBar#template_page_menu_bar::item { + padding: 5px 10px; + background: transparent; + border-radius: 0px; +} +QMenuBar#template_page_menu_bar::item:selected { + background: #FFFFFF; +} +QMenuBar#template_page_menu_bar::item:pressed { + background: #E8E8E8; +} +QMenuBar#template_page_menu_bar QMenu { + background-color: #FFFFFF; + border: 1px solid #D0D0D0; + border-radius: 4px; + padding: 0px; +} +QMenuBar#template_page_menu_bar QMenu::item { + padding: 5px; + color: #000000; + font-size: 11px; +} +QMenuBar#template_page_menu_bar QMenu::item:selected { + background-color: #E6F0FF; + border-radius: 3px; +} +QMenuBar#template_page_menu_bar QMenu::separator { + height: 1px; + background: #F0F0F0; + margin-left: 2px; + margin-right: 2px; + margin-top: 0px; + margin-bottom: 0px; +} +QMenuBar#template_page_menu_bar QMenu::right-arrow { + width: 8px; + height: 8px; +} + +/* Dropdown menu style */ +QMenu { + background: #fff; + border: 1px solid #90AF13; + font-size: 14px; + padding: 0px; +} + +QMenu::item { + padding: 8px 16px; + color: #333; + border: none; + margin: 1px; +} + +QMenu::item:selected { + background: #90AF13; + color: #fff; + border-radius: 2px; +} + +/* ============================================== + 3. GENERAL BUTTON STYLES (Base Level) + ============================================== */ +QPushButton { + background-color: white; + color: black; + font-weight: bold; + border-radius: 5px; + border: 1px solid black; + padding: 5px 14px; + text-align: center; +} + +QPushButton:hover { + background-color: #90AF13; + border: 1px solid #90AF13; + color: white; +} + +QPushButton:pressed { + color: black; + background-color: white; + border: 1px solid black; +} + +QWidget#CustomTitleBar { + background-color: #f4f4f4; +} +QLabel#TitleLabel { + color: #000000; + padding: 0px; + background: transparent; +} +QLabel#LogoLabel { + background: transparent; + color: #ffffff; + font-size: 14px; +} + +QToolButton#MinimizeButton { + background-color: transparent; + color: #000000; + border: 0px; + border-radius: 0px; + font-size: 16px; + border-radius: 0px; +} + +QToolButton#MinimizeButton:hover { + background-color: #f1f1f1; +} + +QToolButton#MinimizeButton:pressed { + background-color: #a6a6a6; +} + +QToolButton#MaxRestoreButton { + background-color: transparent; + color: #000000; + border: 0px; + border-radius: 0px; + font-size: 16px; + border-radius: 0px; +} + +QToolButton#MaxRestoreButton:hover { + background-color: #f1f1f1; +} + +QToolButton#MaxRestoreButton:pressed { + background-color: #a6a6a6; +} + +QToolButton#CloseButton { + background-color: transparent; + color: #000000; + border: 0px; + border-radius: 0px; + font-size: 16px; + border-radius: 0px; +} + +QToolButton#CloseButton:hover { + background-color: #e74c3c; + color: #ffffff; +} + +QToolButton#CloseButton:pressed { + background-color: #c0392b; +} +QWidget#BottomLine { + background-color: #90AF13; +} +/*=======================Logs-Dock===========================*/ +QWidget#logs_dock QLabel { + background-color: #F2F2F2; + color: #000000; + padding: 3px; + font-weight: bold; + font-size: 12px; +} +QWidget#logs_dock QTextEdit { + background-color: #F8F8F8; + border: 1px solid #D0D0D0; + font-family: 'Courier New', monospace; + font-size: 12px; + padding: 5px; + color: #000000; +} +QWidget#logs_dock QScrollBar:vertical { + background: #E0E0E0; /* Light grey for the scrollbar track */ + width: 8px; + margin: 0px 0px 0px 3px; + border-radius: 2px; +} +QWidget#logs_dock QScrollBar::handle:vertical { + background: #A0A0A0; /* Medium grey for the scrollbar handle */ + min-height: 30px; + border-radius: 2px; +} +QWidget#logs_dock QScrollBar::handle:vertical:hover { + background: #707070; /* Darker grey on hover for the handle */ +} +QWidget#logs_dock QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 0px; /* Hides the up/down arrows */ +} +QWidget#logs_dock QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; /* Hides the area between handle and arrows */ +} diff --git a/src/osdagbridge/desktop/resources/vectors/Osdag_logo.svg b/src/osdagbridge/desktop/resources/vectors/Osdag_logo.svg new file mode 100644 index 00000000..1ee3a590 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/Osdag_logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/osdagbridge/desktop/resources/vectors/arrow_down_dark.svg b/src/osdagbridge/desktop/resources/vectors/arrow_down_dark.svg new file mode 100644 index 00000000..2c10661b --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/arrow_down_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/arrow_down_light.svg b/src/osdagbridge/desktop/resources/vectors/arrow_down_light.svg new file mode 100644 index 00000000..52e93659 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/arrow_down_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/arrow_up_dark.svg b/src/osdagbridge/desktop/resources/vectors/arrow_up_dark.svg new file mode 100644 index 00000000..34f7193e --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/arrow_up_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/resources/vectors/arrow_up_light.svg b/src/osdagbridge/desktop/resources/vectors/arrow_up_light.svg new file mode 100644 index 00000000..494d7624 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/arrow_up_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/resources/vectors/checked.svg b/src/osdagbridge/desktop/resources/vectors/checked.svg new file mode 100644 index 00000000..829f9eda --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/checked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/design.svg b/src/osdagbridge/desktop/resources/vectors/design.svg new file mode 100644 index 00000000..a5085160 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/design.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/design_report.svg b/src/osdagbridge/desktop/resources/vectors/design_report.svg new file mode 100644 index 00000000..5c224e91 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/design_report.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/input_dock_active_light.svg b/src/osdagbridge/desktop/resources/vectors/input_dock_active_light.svg new file mode 100644 index 00000000..70151046 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/input_dock_active_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/resources/vectors/input_dock_inactive_light.svg b/src/osdagbridge/desktop/resources/vectors/input_dock_inactive_light.svg new file mode 100644 index 00000000..32bfa48d --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/input_dock_inactive_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/inputs_label_light.svg b/src/osdagbridge/desktop/resources/vectors/inputs_label_light.svg new file mode 100644 index 00000000..4306a92a --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/inputs_label_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/osdagbridge/desktop/resources/vectors/lock_close.svg b/src/osdagbridge/desktop/resources/vectors/lock_close.svg new file mode 100644 index 00000000..8495792d --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/lock_close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/lock_open.svg b/src/osdagbridge/desktop/resources/vectors/lock_open.svg new file mode 100644 index 00000000..5f22789a --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/lock_open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/lock_open_light.svg b/src/osdagbridge/desktop/resources/vectors/lock_open_light.svg new file mode 100644 index 00000000..5f22789a --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/lock_open_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/logs_dock_active_light.svg b/src/osdagbridge/desktop/resources/vectors/logs_dock_active_light.svg new file mode 100644 index 00000000..5d23c855 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/logs_dock_active_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/resources/vectors/logs_dock_inactive_light.svg b/src/osdagbridge/desktop/resources/vectors/logs_dock_inactive_light.svg new file mode 100644 index 00000000..56e27348 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/logs_dock_inactive_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/output_dock_active_light.svg b/src/osdagbridge/desktop/resources/vectors/output_dock_active_light.svg new file mode 100644 index 00000000..7ef0439c --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/output_dock_active_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/resources/vectors/output_dock_inactive_light.svg b/src/osdagbridge/desktop/resources/vectors/output_dock_inactive_light.svg new file mode 100644 index 00000000..a8e65d4a --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/output_dock_inactive_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/resources/vectors/outputs_label_light.svg b/src/osdagbridge/desktop/resources/vectors/outputs_label_light.svg new file mode 100644 index 00000000..cfddf439 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/outputs_label_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/osdagbridge/desktop/resources/vectors/save.svg b/src/osdagbridge/desktop/resources/vectors/save.svg new file mode 100644 index 00000000..c86072a9 --- /dev/null +++ b/src/osdagbridge/desktop/resources/vectors/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/__init__.py b/src/osdagbridge/desktop/ui/__init__.py deleted file mode 100644 index 511085aa..00000000 --- a/src/osdagbridge/desktop/ui/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""UI package (Qt .ui files go here).""" diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/resources.qrc b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/resources.qrc new file mode 100644 index 00000000..a876dcf2 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/resources.qrc @@ -0,0 +1,36 @@ + + + + + + + + + vectors/arrow_down_light.svg + vectors/arrow_down_dark.svg + vectors/arrow_up_light.svg + vectors/arrow_up_dark.svg + + themes/lightstyle.qss + + vectors/design.svg + vectors/save.svg + vectors/checked.svg + vectors/design_report.svg + vectors/lock_open.svg + vectors/lock_close.svg + vectors/Osdag_logo.svg + + vectors/inputs_label_light.svg + vectors/input_dock_active_light.svg + vectors/input_dock_inactive_light.svg + + vectors/logs_dock_active_light.svg + vectors/logs_dock_inactive_light.svg + + vectors/output_dock_active_light.svg + vectors/output_dock_inactive_light.svg + vectors/outputs_label_light.svg + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/resources_rc.py b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/resources_rc.py new file mode 100644 index 00000000..79a25e66 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/resources_rc.py @@ -0,0 +1,1471 @@ +# Resource object code (Python 3) +# Created by: object code +# Created by: The Resource Compiler for Qt version 6.9.2 +# WARNING! All changes made in this file will be lost! + +from PySide6 import QtCore + +qt_resource_data = b"\ +\x00\x00\x04\xe7\ +\x00\ +\x00\x15\xe8x\xda\xd5X]O\xdb<\x14\xbeG\xe2?\ +X\xea\xc5>\xb4\xae-\x85\x8e\x05\xbd\x17\xfd\x82!\x15\ +\x18\xb4\xdb\xc4n\x90\x93\xb8\xad\x85\x1bg\x8eC\xe1\x9d\ +\xf8\xef\xef\xb1\x9b\xef&n`\xef\xcdb\x0du\xb6s\ +\xce\xe3\xc7\x8f\xcf9N\xeb=\xfa\xe7E\xcf\xfe\x1eB\ +\xe8j:\xea\x9f\xa1\xb3o\xe7h:\xbb\x9d\x8c\xa7_\ +\xc6\xe3\x19j\xa2\xab\x9b\xb3\xfe\xe5\xf9\xcf\xf1\x08\x0dn\ +\xd1\xf4\xebxx~z><\x9f\xdd\xeaw^\xe6\x06\ +\xbdo\xed\xef\xed\xef\xb5^\x05\xaf\xf3\x11\x9dM\xae\x06\ +\xfdI\x04\x0f\xbd\x9d\x10\x1cH4\xf5\x89C\xe7\xd4y\ +\xf7Z@\xd7\x17\x98z?\xa8\xe7\xf25\xfa\xad\x8d \ +\x1b;\xf7\x0b\xc1C\xcfm:\x9cqa\xa1\xc6\xfcP\ +\xb5\x93h\x9c\x0b\x97@o\xc7\x7fD\x01g\xd4E\x8d\ +\xcfm<\xeft\xa3\xf1\x15\x16\x0b\xeaY\xa8\xed?F\ +=>v]\xea-\xe2\xaeg\xc5\xc3\xf5\x8cs6\xa3\ +\xbe\xc1\xeb\xa9~\x22\x1bqg[?&(\xfd\xd3\x04\ +J\xe2\xf8\x00&\x1c$x\xe6\xdc\x93\xcd\x80\xfeK\xe0\ +\xcd\xb4wc\xac)\xb0K\xc3 \x0b\xff\x97/\xb8O\ +\x84|jbF\x17\xde\x8ax\xd2B}\xf5\xf3\xfb\x10\ +~\x13\xb1Y\xd3\xf5\xd4gT\xc2\x7f-k\x89=\x97\ +\x11\xc3\xd2Fm\xd5b.@\x13g\x8c\xdb\x98\xa1\xe1\ +\x928\xf76\x7fDS\xf9\x04\x06\xf4\x0e\xe9\xbe\x01\xf4\ +\xfd\xdeF\x9f\x82\x8c-w\xbb\xf1\xe2\x03\x1f;z\xf1\ +\xbd\x98\xf5\xc4\x94e\xc1\x8eS\x07K.b\xabk\xea\ +\xca%X\xec%\x16\x97\x84.\x962\xd7U\xc2wW\ +?\xe5\x14v\xd3\x17K4\xa5\x9fj`\xd6\x92?\x90\ +\x04^\x89\xe7#\xfd\x18\x0c8\xaa\x8f\xb8&]\xc7\x18\ +\xea,\x8e\xae\xf0\x028\x0f\x05{k\xb5\x1e\x88\x03.\ +\x82V\xe4\xe3c\xf0\xb0x\x97H\xfb\x82x\xe1\x00\x8b\ +\x86$+\x9faI\xee|x\xf3\x0et\x13\xde\xd9X\ +\x98\x14\x7f\xa8\x9aI\xf1\xdbGi\x877 \x04\x06b\ +\x9f\xc9\xebG\xb0\xc8\x8czR,\x16\x92\x02{\xa0\x1d\ +\x01\xd26\x9d\x8c\xba\xae\xad\x800 \xabl\x1f\xb2g\ +\xbc\xb69_\x90 \xa8\xb06>V\xad\x965\xa4\xc7\ +\xebF\x9f\x12m$G\xb8\x84\xa1CC\xe8\xab\x85\xab\ +z\xd7L\xe2\xc8F\x86\xce+\xfc\x19\xb6*\xa1e\xdc\ +;m\x17h)\x9c\xf7\xfa>\x03\x022\xcb\x06\xa1$\ +\xe4\x94\x0a\xb3\x01\x9e\xa1\xe5\xd2L\x93\x91\xb9\xb42\xb1\ +=\xea\x16\x1bC[\xfd\x92\xfb\xd9\xd0\x1e\xf5\xda\x5cJ\ +\xbez\xf9&i/M,D\x9a=\xa38z\xbc\x15\ +F\x8f\xd3\xdc\x07\xf1~\x04)\x05r\xae\x87\x94I\x14\ +\xa4\xd1\xbe\x5c\x95\x9bXU3\xebeephN\xc2\ +\x06\xad\x1d\xab\x08\xd13\xe4\x97\x18\x86\xc7=RH\xfd\ +\x9dR\x17\xe6H\x90[B&@\x97K\xed \xc7\xe6\ ++*\xaa.TT\xe3\xcb\xf1\x0d\x94T\x83o\xb3\xd9\ +\xd5eRY\x0dp@\xd0\x84<\x10\xf6\xfa\xaa\xeak\ +\x18,\x07!\x88\xca\xab>J\xeb%\x90\x92_\xaf\xcd\ +`Vv\x17\xd7\x91xl\xce\xdc\x13T\xca\xc4\x91!\ +;g\xed\xe5C\x7f\xaa\x0bI\x1e\xe5\xa6\xb0\xb1\x90\x93\ +)gr\xab($\xe3\xed\xb0\x90\xdb\xbd]\x02-\x10\ +\xb0\xe5\xac\x10\xe2K\xc81\xb3YM\xc4\xc6\xd5\x0f\xea\ +.\x88l\x0c\xc3\x00N\xfd\x8cJF\x06*-\xa3\xdd\ +\xf5\xaf\x0a\x0d\x13l\x13\xd6\xd0\xaf\xe9\x9f\x05\x98\xc6|\ +m\xce\xb5\xa9\xf5\x09_\xf0\x9cqs\x82.\xadg\xb6\ +\xc3@Zxo\x88n\x5cP\x8f\xae`\xc6.\xa9V\ +{,-\xc7\xdb\xbbk\xea,\xb8\x9ey\xfa\x0e\xd4;\ +\xa59\xef\xa8V\xc3Pee\x91\x98\xc2=\xd5JM\ +\xe1\xc7\x1b\x02r\x12\x7f\x1b\x97\x05\xdc\x7f\xc2f\xd1\xd4\ +\x9f\xf09d<\xf8\xcb\xa8\xcc@\xde\xc9\x22\xf9t\xe8\ +t\x9d\xaa\xd3k4\xbd\x9bU\xa7\xdd\xfd|`G\xf1\ +$\x8au\x03]\xe1L\xa8G\xea\x04\xf1g\x95U+\ +\x12\x1c\x84\xa6\xa09\xe2\xce\xbd!\x09\xea\x1c\x18yf\ +0\xff\xce\x85\xf9\xe8\xba\x22\xa2\xa5%\xf7\x81j\xb5\xae\ +?\xdd\xfc\x96\xe5\xf2d\xd5%\xff\xb9\x14\xd4\x0c\xf2\xdf\ +\xd8\xa5\xd2\x84\xebX\xb5\x9aW\x01\xedw\x8eW\x94=\ +Y\xe8\xcd\x90\x87\x82\x82\x14.\xc9\xfa\xcd\x07\xb4\xe2\x1e\ +W\xd7rb\xfc\x10Q\xa7\xdc/_\xcb\xd4\x11\x9c1\ +Hf\x16\xc8O\xc25\x98\x95_\x93\xda\xaa\x9d \xa8\ +\x9c&\x8a7\xb4\x10\xe4\x09\xc0\x08$\x97\x04\x05\xda\x88\ +\xaar\xe1|\x81U\xb5\x99\xa5\x95m\xe6CO\xf2\xaf\ +[uhL[\x90\xc2\x8e\xbe\x9c\x98\xe1\xf7\xdb\xaai\ +\xf8\x17\x04\xac\xaf\xaa\xf0G\x9fa\xe2\x05\xac\xa0\xd2\x8f\ +\xab\xf1n\xfb\xff\x05Zu\xe2\x01\xee\xa7\xb6j\x1a\xee\ +\x08\x8b{\x98\xa5\xe1B`\xdb\xbc\x13\xe3\xce\xa0\xdd\xe9\ +\x1d\x14\xd2dp\x98\x13\xff\x1fr\xc3Ah\xe7\x87\x8b\ +\x17,\xb5z\x05\xe8\x0buI\xa0\xbd\x87~K\xdfG\ +\xf4e&\xa8\x8fB\xdd\x8b\x0c(r\xc3e\xf4\xe8\xdb\ +C\x1e\x0a\x04t\x8cl\x22\xd7\x84x1+\xf0\xb7\x00\ +\xed??\x04\x81\x7f\ +\x00\x00\x00\xb2\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x222\ +4px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2224px\x22 fill=\ +\x22#90af13\x22>\ +\x00\x00\x02-\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x0e;\ +<\ +svg width=\x22149\x22 \ +height=\x22141\x22 vie\ +wBox=\x220 0 149 14\ +1\x22 fill=\x22none\x22 x\ +mlns=\x22http://www\ +.w3.org/2000/svg\ +\x22>\x0d\x0a\x0d\x0a<\ +path d=\x22M130.212\ + 67.3074L115.887\ + 51.8725L130.121\ + 36.1514L130.212\ + 67.3074Z\x22 fill=\ +\x22black\x22/>\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x02\xfe\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x02\x07\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x021\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +\ +\x00\x00\x01\xa4\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x02\xd3\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +\x00\x00\x05O\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x08+\ +<\ +svg width=\x2236\x22 h\ +eight=\x22922\x22 view\ +Box=\x220 0 36 922\x22\ + fill=\x22none\x22 xml\ +ns=\x22http://www.w\ +3.org/2000/svg\x22>\ +\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x02\xde\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x021\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\ +\x00\x00\x0aV\ +<\ +svg width=\x2236\x22 h\ +eight=\x22918\x22 view\ +Box=\x220 0 36 918\x22\ + fill=\x22none\x22 xml\ +ns=\x22http://www.w\ +3.org/2000/svg\x22>\ +\x0d\x0a\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x05O\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x02\xbb\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +\x00\x00\x02/\ +<\ +svg width=\x2240\x22 h\ +eight=\x2240\x22 viewB\ +ox=\x220 0 40 40\x22 f\ +ill=\x22none\x22 xmlns\ +=\x22http://www.w3.\ +org/2000/svg\x22>\x0d\x0a\ +\x0d\x0a\x0d\x0a\ +\x00\x00\x01\x9d\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x01\xa2\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#000000\x22>\ +\x00\x00\x025\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 height=\x224\ +0px\x22 viewBox=\x220 \ +-960 960 960\x22 wi\ +dth=\x2240px\x22 fill=\ +\x22#FFFFFF\x22>\ +" + +qt_resource_name = b"\ +\x00\x07\ +\x0c\xba\xb6s\ +\x00v\ +\x00e\x00c\x00t\x00o\x00r\x00s\ +\x00\x06\ +\x07\xae\xc3\xc3\ +\x00t\ +\x00h\x00e\x00m\x00e\x00s\ +\x00\x0e\ +\x03\x9b1c\ +\x00l\ +\x00i\x00g\x00h\x00t\x00s\x00t\x00y\x00l\x00e\x00.\x00q\x00s\x00s\ +\x00\x0b\ +\x01d\x8d\x87\ +\x00c\ +\x00h\x00e\x00c\x00k\x00e\x00d\x00.\x00s\x00v\x00g\ +\x00\x1b\ +\x0aa\xaa'\ +\x00i\ +\x00n\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00a\x00c\x00t\x00i\x00v\x00e\ +\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x0e\ +\x06\xb1\x9b\x07\ +\x00O\ +\x00s\x00d\x00a\x00g\x00_\x00l\x00o\x00g\x00o\x00.\x00s\x00v\x00g\ +\x00\x0e\ +\x0d\xd6\xeag\ +\x00l\ +\x00o\x00c\x00k\x00_\x00c\x00l\x00o\x00s\x00e\x00.\x00s\x00v\x00g\ +\x00\x1a\ +\x0b}\x5cG\ +\x00l\ +\x00o\x00g\x00s\x00_\x00d\x00o\x00c\x00k\x00_\x00a\x00c\x00t\x00i\x00v\x00e\x00_\ +\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x13\ +\x0cPg\xa7\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00d\x00o\x00w\x00n\x00_\x00d\x00a\x00r\x00k\x00.\x00s\ +\x00v\x00g\ +\x00\x1e\ +\x08a\xb9\xc7\ +\x00o\ +\x00u\x00t\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00i\x00n\x00a\x00c\x00t\ +\x00i\x00v\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x0a\ +\x0f\xec\x03\xe7\ +\x00d\ +\x00e\x00s\x00i\x00g\x00n\x00.\x00s\x00v\x00g\ +\x00\x12\ +\x0aDDG\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00u\x00p\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\ +\x00g\ +\x00\x16\ +\x0e\x16='\ +\x00i\ +\x00n\x00p\x00u\x00t\x00s\x00_\x00l\x00a\x00b\x00e\x00l\x00_\x00l\x00i\x00g\x00h\ +\x00t\x00.\x00s\x00v\x00g\ +\x00\x0d\ +\x005w\xc7\ +\x00l\ +\x00o\x00c\x00k\x00_\x00o\x00p\x00e\x00n\x00.\x00s\x00v\x00g\ +\x00\x14\ +\x01\xd3}\xa7\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00d\x00o\x00w\x00n\x00_\x00l\x00i\x00g\x00h\x00t\x00.\ +\x00s\x00v\x00g\ +\x00\x17\ +\x0d\xa0\xcd'\ +\x00o\ +\x00u\x00t\x00p\x00u\x00t\x00s\x00_\x00l\x00a\x00b\x00e\x00l\x00_\x00l\x00i\x00g\ +\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x11\ +\x03\xf9t'\ +\x00a\ +\x00r\x00r\x00o\x00w\x00_\x00u\x00p\x00_\x00d\x00a\x00r\x00k\x00.\x00s\x00v\x00g\ +\ +\x00\x11\ +\x08\xb1e\xc7\ +\x00d\ +\x00e\x00s\x00i\x00g\x00n\x00_\x00r\x00e\x00p\x00o\x00r\x00t\x00.\x00s\x00v\x00g\ +\ +\x00\x1c\ +\x0ap\xe4'\ +\x00o\ +\x00u\x00t\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00a\x00c\x00t\x00i\x00v\ +\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x1c\ +\x01\xd8[\xc7\ +\x00l\ +\x00o\x00g\x00s\x00_\x00d\x00o\x00c\x00k\x00_\x00i\x00n\x00a\x00c\x00t\x00i\x00v\ +\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x1d\ +\x0e\xaf\xb9\xe7\ +\x00i\ +\x00n\x00p\x00u\x00t\x00_\x00d\x00o\x00c\x00k\x00_\x00i\x00n\x00a\x00c\x00t\x00i\ +\x00v\x00e\x00_\x00l\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\ +\x00\x08\ +\x08\xc8U\xe7\ +\x00s\ +\x00a\x00v\x00e\x00.\x00s\x00v\x00g\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x16\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x13\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00/T\ +\x00\x00\x01\x9b\x13E\x17;\ +\x00\x00\x00H\x00\x00\x00\x00\x00\x01\x00\x00\x04\xeb\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x02\x22\x00\x00\x00\x00\x00\x01\x00\x0026\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x03\x12\x00\x00\x00\x00\x00\x01\x00\x00I\x0a\ +\x00\x00\x01\x9a\xfc\x9f}A\ +\x00\x00\x02\x84\x00\x00\x00\x00\x00\x01\x00\x00>\xc5\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x07\xd2\ +\x00\x00\x01\x9b\x13\xd0_\xa8\ +\x00\x00\x01J\x00\x00\x00\x00\x00\x01\x00\x00\x1dS\ +\x00\x00\x01\x9a\xfc\x9f}M\ +\x00\x00\x02\xac\x00\x00\x00\x00\x00\x01\x00\x00D\x18\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x03\x90\x00\x00\x00\x00\x00\x01\x00\x00LQ\ +\x00\x00\x01\x9b\x13E\x17;\ +\x00\x00\x01\xa6\x00\x00\x00\x00\x00\x01\x00\x00!\xd2\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x00d\x00\x00\x00\x00\x00\x01\x00\x00\x05\xa1\ +\x00\x00\x01\x9a\xfc\x9f};\ +\x00\x00\x02\xd4\x00\x00\x00\x00\x00\x01\x00\x00F\xd7\ +\x00\x00\x01\x9a\xfc\x9f}K\ +\x00\x00\x00\xe4\x00\x00\x00\x00\x00\x01\x00\x00\x19\x13\ +\x00\x00\x01\x9a\xfc\x9f}A\ +\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x1e\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x02P\x00\x00\x00\x00\x00\x01\x00\x004k\ +\x00\x00\x01\x9b\x07\x002e\ +\x00\x00\x00\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x16\x11\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x01\xd0\x00\x00\x00\x00\x00\x01\x00\x00'%\ +\x00\x00\x01\x9b\x07\x002a\ +\x00\x00\x03P\x00\x00\x00\x00\x00\x01\x00\x00J\xab\ +\x00\x00\x01\x9a\xfc\x9f}<\ +\x00\x00\x01\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x1e\xfb\ +\x00\x00\x01\x9b\x13E\x179\ +\x00\x00\x00&\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x9b\x13\xd50\xdc\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/themes/darkstyle.qss b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/themes/darkstyle.qss new file mode 100644 index 00000000..f9c6f9ac --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/themes/darkstyle.qss @@ -0,0 +1,32 @@ +/* ============================================== + OSDAG GUI STYLESHEET - ORGANIZED BY SPECIFICITY + ============================================== */ + +/* ============================================== + 1. GLOBAL STYLES (Least Specific) + ============================================== */ +* { + font-family: "Ubuntu Sans"; +} + +QMainWindow { + background-color: #282828; + border: 1px solid #6B7D20; + margin: 0px; + padding: 0px; +} + +QTabWidget { + background-color: #333333; + border: 0px; +} + +QToolTip { + background-color: #2B2B2B; + color: #D0D0D0; + border: 1px solid #6B7D20; + padding: 2px 2px; + font-size: 12px; + border-radius: 0px; + qproperty-alignment: AlignVCenter; +} \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/themes/lightstyle.qss b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/themes/lightstyle.qss new file mode 100644 index 00000000..452eeeb6 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/themes/lightstyle.qss @@ -0,0 +1,243 @@ +/* ============================================== + OSDAG GUI STYLESHEET - ORGANIZED BY SPECIFICITY + ============================================== */ + +/* ============================================== + 1. GLOBAL STYLES (Least Specific) + ============================================== */ +QMainWindow { + background-color: #f4f4f4; + border: 1px solid #90af13; + margin: 0px; + padding: 0px; +} + +QToolTip { + background-color: #FFFFFF; + color: #000000; + border: 1px solid #90AF13; + padding: 2px 2px; + font-size: 12px; + border-radius: 0px; + qproperty-alignment: AlignVCenter; +} +QSplitter::handle { + background-color: #D0D0D0; +} + +/* Global Checkbox Style */ +QCheckBox { + font-size: 10px; + color: #333; + spacing: 6px; +} +QCheckBox::indicator { + width: 16px; + height: 16px; + border: 1px solid #333333; + border-radius: 3px; + background-color: #ffffff; +} +QCheckBox::indicator:hover { + border: 1px solid #555555; +} +QCheckBox::indicator:checked { + background-color: #ffffff; + border: 1px solid #333333; + image: url(:/vectors/checked.svg); +} + +QMenuBar#template_page_menu_bar { + background-color: #F4F4F4; + color: #000000; + padding: 0px; +} +QMenuBar#template_page_menu_bar::item { + padding: 5px 10px; + background: transparent; + border-radius: 0px; +} +QMenuBar#template_page_menu_bar::item:selected { + background: #FFFFFF; +} +QMenuBar#template_page_menu_bar::item:pressed { + background: #E8E8E8; +} +QMenuBar#template_page_menu_bar QMenu { + background-color: #FFFFFF; + border: 1px solid #D0D0D0; + border-radius: 4px; + padding: 0px; +} +QMenuBar#template_page_menu_bar QMenu::item { + padding: 5px; + color: #000000; + font-size: 11px; +} +QMenuBar#template_page_menu_bar QMenu::item:selected { + background-color: #E6F0FF; + border-radius: 3px; +} +QMenuBar#template_page_menu_bar QMenu::separator { + height: 1px; + background: #F0F0F0; + margin-left: 2px; + margin-right: 2px; + margin-top: 0px; + margin-bottom: 0px; +} +QMenuBar#template_page_menu_bar QMenu::right-arrow { + width: 8px; + height: 8px; +} + +/* Dropdown menu style */ +QMenu { + background: #fff; + border: 1px solid #90AF13; + font-size: 14px; + padding: 0px; +} + +QMenu::item { + padding: 8px 16px; + color: #333; + border: none; + margin: 1px; +} + +QMenu::item:selected { + background: #90AF13; + color: #fff; + border-radius: 2px; +} + +/* ============================================== + 3. GENERAL BUTTON STYLES (Base Level) + ============================================== */ +QPushButton { + background-color: white; + color: black; + font-weight: bold; + border-radius: 5px; + border: 1px solid black; + padding: 5px 14px; + text-align: center; +} + +QPushButton:hover { + background-color: #90AF13; + border: 1px solid #90AF13; + color: white; +} + +QPushButton:pressed { + color: black; + background-color: white; + border: 1px solid black; +} + +QWidget#CustomTitleBar { + background-color: #f4f4f4; +} +QLabel#TitleLabel { + color: #000000; + padding: 0px; + background: transparent; +} +QLabel#LogoLabel { + background: transparent; + color: #ffffff; + font-size: 14px; +} + +QToolButton#MinimizeButton { + background-color: transparent; + color: #000000; + border: 0px; + border-radius: 0px; + font-size: 16px; + border-radius: 0px; +} + +QToolButton#MinimizeButton:hover { + background-color: #f1f1f1; +} + +QToolButton#MinimizeButton:pressed { + background-color: #a6a6a6; +} + +QToolButton#MaxRestoreButton { + background-color: transparent; + color: #000000; + border: 0px; + border-radius: 0px; + font-size: 16px; + border-radius: 0px; +} + +QToolButton#MaxRestoreButton:hover { + background-color: #f1f1f1; +} + +QToolButton#MaxRestoreButton:pressed { + background-color: #a6a6a6; +} + +QToolButton#CloseButton { + background-color: transparent; + color: #000000; + border: 0px; + border-radius: 0px; + font-size: 16px; + border-radius: 0px; +} + +QToolButton#CloseButton:hover { + background-color: #e74c3c; + color: #ffffff; +} + +QToolButton#CloseButton:pressed { + background-color: #c0392b; +} +QWidget#BottomLine { + background-color: #90AF13; +} +/*=======================Logs-Dock===========================*/ +QWidget#logs_dock QLabel { + background-color: #F2F2F2; + color: #000000; + padding: 3px; + font-weight: bold; + font-size: 12px; +} +QWidget#logs_dock QTextEdit { + background-color: #F8F8F8; + border: 1px solid #D0D0D0; + font-family: 'Courier New', monospace; + font-size: 12px; + padding: 5px; + color: #000000; +} +QWidget#logs_dock QScrollBar:vertical { + background: #E0E0E0; /* Light grey for the scrollbar track */ + width: 8px; + margin: 0px 0px 0px 3px; + border-radius: 2px; +} +QWidget#logs_dock QScrollBar::handle:vertical { + background: #A0A0A0; /* Medium grey for the scrollbar handle */ + min-height: 30px; + border-radius: 2px; +} +QWidget#logs_dock QScrollBar::handle:vertical:hover { + background: #707070; /* Darker grey on hover for the handle */ +} +QWidget#logs_dock QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 0px; /* Hides the up/down arrows */ +} +QWidget#logs_dock QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; /* Hides the area between handle and arrows */ +} diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/Osdag_logo.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/Osdag_logo.svg new file mode 100644 index 00000000..1ee3a590 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/Osdag_logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_down_dark.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_down_dark.svg new file mode 100644 index 00000000..2c10661b --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_down_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_down_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_down_light.svg new file mode 100644 index 00000000..52e93659 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_down_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_up_dark.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_up_dark.svg new file mode 100644 index 00000000..34f7193e --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_up_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_up_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_up_light.svg new file mode 100644 index 00000000..494d7624 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/arrow_up_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/checked.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/checked.svg new file mode 100644 index 00000000..829f9eda --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/checked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/design.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/design.svg new file mode 100644 index 00000000..a5085160 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/design.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/design_report.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/design_report.svg new file mode 100644 index 00000000..5c224e91 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/design_report.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/input_dock_active_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/input_dock_active_light.svg new file mode 100644 index 00000000..70151046 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/input_dock_active_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/input_dock_inactive_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/input_dock_inactive_light.svg new file mode 100644 index 00000000..32bfa48d --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/input_dock_inactive_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/inputs_label_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/inputs_label_light.svg new file mode 100644 index 00000000..4306a92a --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/inputs_label_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_close.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_close.svg new file mode 100644 index 00000000..8495792d --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_open.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_open.svg new file mode 100644 index 00000000..5f22789a --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_open_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_open_light.svg new file mode 100644 index 00000000..5f22789a --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/lock_open_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/logs_dock_active_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/logs_dock_active_light.svg new file mode 100644 index 00000000..5d23c855 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/logs_dock_active_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/logs_dock_inactive_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/logs_dock_inactive_light.svg new file mode 100644 index 00000000..56e27348 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/logs_dock_inactive_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/output_dock_active_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/output_dock_active_light.svg new file mode 100644 index 00000000..7ef0439c --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/output_dock_active_light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/output_dock_inactive_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/output_dock_inactive_light.svg new file mode 100644 index 00000000..a8e65d4a --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/output_dock_inactive_light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/outputs_label_light.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/outputs_label_light.svg new file mode 100644 index 00000000..cfddf439 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/outputs_label_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/save.svg b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/save.svg new file mode 100644 index 00000000..c86072a9 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/__pycache__/resources/vectors/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/dialogs/additional_inputs.py b/src/osdagbridge/desktop/ui/dialogs/additional_inputs.py new file mode 100644 index 00000000..a3a6f1e1 --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/additional_inputs.py @@ -0,0 +1,4766 @@ +""" +Additional Inputs Widget for Highway Bridge Design +Provides detailed input fields for manual bridge parameter definition +""" +import math +import sys +import os +from PySide6.QtWidgets import ( + QWidget, QVBoxLayout, QHBoxLayout, QTabWidget, QTabBar, QLabel, QLineEdit, + QComboBox, QGroupBox, QFormLayout, QPushButton, QScrollArea, + QCheckBox, QMessageBox, QSizePolicy, QSpacerItem, QStackedWidget, + QFrame, QGridLayout, QTableWidget, QTableWidgetItem, QHeaderView, + QTextEdit, QDialog, QSizePolicy, QSizeGrip +) +from PySide6.QtCore import Qt, Signal, QSize +from PySide6.QtGui import QDoubleValidator, QIntValidator, QStandardItemModel + +from osdagbridge.core.bridge_components.super_structure.girder import properties as girder_properties +from osdagbridge.core.utils.common import * +from osdagbridge.desktop.ui.utils.custom_titlebar import CustomTitleBar +from osdagbridge.desktop.ui.utils.rolled_section_preview import RolledSectionPreview + +# ================================================================================= +# CENTRALIZED STYLING +# ================================================================================= + +def get_combobox_style(): + """Return the common stylesheet for dropdowns with the SVG icon from resources.""" + return """ + QComboBox{ + padding: 1px 7px; + border: 1px solid black; + border-radius: 5px; + background-color: white; + color: black; + } + QComboBox::drop-down{ + subcontrol-origin: padding; + subcontrol-position: top right; + border-left: 0px; + } + QComboBox::down-arrow{ + image: url(:/vectors/arrow_down_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox::down-arrow:on { + image: url(:/vectors/arrow_up_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox QAbstractItemView{ + background-color: white; + border: 1px solid black; + outline: none; + } + QComboBox QAbstractItemView::item{ + color: black; + background-color: white; + border: none; + border: 1px solid white; + border-radius: 0; + padding: 2px; + } + QComboBox QAbstractItemView::item:hover{ + border: 1px solid #90AF13; + background-color: #90AF13; + color: black; + } + QComboBox QAbstractItemView::item:selected{ + background-color: #90AF13; + color: black; + border: 1px solid #90AF13; + } + QComboBox QAbstractItemView::item:selected:hover{ + background-color: #90AF13; + color: black; + border: 1px solid #94b816; + } + QComboBox:disabled{ + background: #f1f1f1; + color: #666; + } + """ + + +def get_lineedit_style(): + """Return the shared stylesheet for line edits in the section inputs.""" + return """ + QLineEdit { + padding: 1px 7px; + border: 1px solid #070707; + border-radius: 6px; + background-color: white; + color: #000000; + font-weight: normal; + } + QLineEdit:disabled{ + background: #f1f1f1; + color: #666; + } + QLineEdit:read-only{ + background: #f6f6f6; + color: #555555; + } + QLineEdit:hover { + border: 1px solid #5d5d5d; + } + """ + + +def apply_field_style(widget): + """Apply the appropriate style to combo boxes and line edits.""" + widget.setMinimumHeight(28) + if isinstance(widget, QComboBox): + widget.setStyleSheet(get_combobox_style()) + elif isinstance(widget, QLineEdit): + widget.setStyleSheet(get_lineedit_style()) + + +def create_action_button_bar(parent=None): + """Create a standardized Defaults/Save bar with gray backing.""" + frame = QFrame(parent) + frame.setObjectName("actionButtonBar") + frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + frame.setStyleSheet(""" + QFrame#actionButtonBar { + background-color: #ededed; + border: 1px solid #c8c8c8; + border-radius: 6px; + } + QFrame#actionButtonBar QPushButton { + background-color: #ffffff; + color: #2f2f2f; + font-weight: 600; + border: 1px solid #8c8c8c; + border-radius: 4px; + padding: 6px 24px; + min-width: 120px; + } + QFrame#actionButtonBar QPushButton:hover { + background-color: #f6f6f6; + } + QFrame#actionButtonBar QPushButton:pressed { + background-color: #e0e0e0; + } + """) + + layout = QHBoxLayout(frame) + layout.setContentsMargins(22, 10, 22, 10) + layout.setSpacing(12) + layout.addStretch() + + defaults_button = QPushButton("Defaults", frame) + save_button = QPushButton("Save", frame) + layout.addWidget(defaults_button) + layout.addWidget(save_button) + layout.addStretch() + + return frame, defaults_button, save_button + + +SECTION_NAV_BUTTON_STYLE = """ + QPushButton { + background-color: #f4f4f4; + border: 2px solid #d2d2d2; + border-radius: 12px; + padding: 20px 16px; + text-align: left; + font-weight: bold; + font-size: 12px; + color: #333333; + } + QPushButton:hover { + border-color: #b5b5b5; + } + QPushButton:checked { + background-color: #9ecb3d; + border-color: #7da523; + color: #ffffff; + } +""" + + +class CheckableComboBox(QComboBox): + """Multi-select combo box that keeps track of checked girders.""" + + checkedItemsChanged = Signal() + + def __init__(self, parent=None): + super().__init__(parent) + model = QStandardItemModel(self) + self.setModel(model) + self._updating_selection = False + model.itemChanged.connect(self._handle_item_changed) + + def addItem(self, text, userData=None): + super().addItem(text, userData) + self._initialize_item(self.count() - 1) + + def addItems(self, texts): + for text in texts: + self.addItem(text) + + def _initialize_item(self, index): + item = self.model().item(index) + if not item: + return + item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) + if item.text().lower() == "all": + item.setData(Qt.Checked, Qt.CheckStateRole) + else: + item.setData(Qt.Unchecked, Qt.CheckStateRole) + + def _handle_item_changed(self, item): + if self._updating_selection or item is None: + return + self._updating_selection = True + try: + text = item.text().strip().lower() + if text == "all": + if item.checkState() == Qt.Checked: + self._uncheck_non_all_items() + else: + if item.checkState() == Qt.Checked: + self._uncheck_all_item() + finally: + self._updating_selection = False + self.checkedItemsChanged.emit() + + def _uncheck_non_all_items(self): + model = self.model() + for row in range(model.rowCount()): + item = model.item(row) + if not item: + continue + if item.text().strip().lower() == "all": + continue + item.setCheckState(Qt.Unchecked) + + def _uncheck_all_item(self): + model = self.model() + for row in range(model.rowCount()): + item = model.item(row) + if item and item.text().strip().lower() == "all": + item.setCheckState(Qt.Unchecked) + break + + def checked_items(self, include_all=False): + model = self.model() + selected = [] + all_checked = False + for row in range(model.rowCount()): + item = model.item(row) + if not item or item.checkState() != Qt.Checked: + continue + text = item.text() + if text.strip().lower() == "all": + all_checked = True + if include_all: + selected.append(text) + else: + selected.append(text) + if all_checked and not include_all: + return [] + return [text for text in selected if text.strip().lower() != "all"] + +# ================================================================================= +# MAIN IMPLEMENTATION +# ================================================================================= + +class AdditionalInputs(QDialog): + """Main dialog for Additional Inputs with tabbed interface""" + + def __init__(self, footpath_value="None", carriageway_width=7.5, parent=None): + super().__init__(parent) + self.setObjectName("AdditionalInputs") + self.resize(1024, 720) + self.setMinimumSize(900, 520) + self.setSizeGripEnabled(True) + self.footpath_value = footpath_value + self.carriageway_width = carriageway_width + self.init_ui() + self.setStyleSheet(""" + QDialog { + background-color: #ffffff; + border: 1px solid #90AF13; + } + """) + + def setupWrapper(self): + self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowSystemMenuHint) + + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(1, 1, 1, 1) + main_layout.setSpacing(0) + + self.title_bar = CustomTitleBar() + self.title_bar.setTitle("Additional Inputs") + main_layout.addWidget(self.title_bar) + + self.content_widget = QWidget(self) + main_layout.addWidget(self.content_widget, 1) + + size_grip = QSizeGrip(self) + size_grip.setFixedSize(16, 16) + + overlay = QHBoxLayout() + overlay.setContentsMargins(0, 0, 4, 4) + overlay.addStretch(1) + overlay.addWidget(size_grip, 0, Qt.AlignBottom | Qt.AlignRight) + main_layout.addLayout(overlay) + + def init_ui(self): + self.setupWrapper() + + main_layout = QVBoxLayout(self.content_widget) + main_layout.setContentsMargins(5, 5, 5, 5) + + # Main tab widget + self.tabs = QTabWidget() + self.tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + self.stretching_tab_bar = QTabBar() + self.stretching_tab_bar.setElideMode(Qt.ElideRight) + self.tabs.setTabBar(self.stretching_tab_bar) + self.tabs.setStyleSheet(""" + QTabWidget::pane { + border: 1px solid #d1d1d1; + background-color: #ffffff; + border-radius: 6px; + } + QTabBar::tab { + font-weight: bold; + font-size: 12px; + background: #ffffff; + color: #3a3a3a; + border: 1px solid #d1d1d1; + padding: 10px 22px; + } + QTabBar::tab:selected { + background: #90AF13; + color: #ffffff; + border: 1px solid #90AF13; + } + QTabBar::tab:hover { + background: #90AF13; + color: #ffffff; + } + """) + + # Sub-Tab 1: Typical Section Details + self.typical_section_tab = TypicalSectionDetailsTab(self.footpath_value, self.carriageway_width) + self.tabs.addTab(self.typical_section_tab, "Typical Section Details") + + # Sub-Tab 2: Member Properties + self.section_properties_tab = SectionPropertiesTab() + self.tabs.addTab(self.section_properties_tab, "Member Properties") + + # Sub-Tab 3: Loading + self.loading_tab = LoadingTab() + self.tabs.addTab(self.loading_tab, "Loading") + + # Sub-Tab 4: Support Conditions + support_tab = self._build_support_conditions_tab() + self.tabs.addTab(support_tab, "Support Conditions") + + # Sub-Tab 5: Design Options + design_options_tab = self._build_design_options_tab() + self.tabs.addTab(design_options_tab, "Design Options") + + # Sub-Tab 6: Design Options (Cont.) + analysis_design_tab = self.create_placeholder_tab( + "Design Options (Cont.)", + "This tab will contain:\n\n" + + "• Analysis Method\n" + + "• Design Code Options\n" + + "• Safety Factors\n" + + "• Other Design Parameters\n\n" + + "Implementation in progress..." + ) + self.tabs.addTab(analysis_design_tab, "Design Options (Cont.)") + + main_layout.addWidget(self.tabs) + + + action_bar, self.defaults_button, self.save_button = create_action_button_bar() + self.defaults_button.clicked.connect(lambda: self._show_placeholder_message("Defaults")) + self.save_button.clicked.connect(lambda: self._show_placeholder_message("Save")) + main_layout.addSpacing(6) + main_layout.addWidget(action_bar) + + def accept(self): + girder_tab = getattr(getattr(self, "section_properties_tab", None), "girder_tab", None) + if girder_tab and not girder_tab.validate_member_properties(): + return + super().accept() + + def _show_placeholder_message(self, action_name): + """Show placeholder message for action buttons""" + QMessageBox.information(self, action_name, "This action will be available in an upcoming update.") + + def _build_support_conditions_tab(self): + """Build the Support Conditions tab matching reference design""" + widget = QWidget() + widget.setStyleSheet("background-color: #f5f5f5;") + + main_layout = QVBoxLayout(widget) + main_layout.setContentsMargins(12, 12, 12, 12) + main_layout.setSpacing(12) + + # Main card + card = QFrame() + card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + card_layout = QVBoxLayout(card) + card_layout.setContentsMargins(16, 16, 16, 16) + card_layout.setSpacing(16) + + label_style = "font-size: 11px; color: #3a3a3a; background: transparent; border: none;" + heading_style = "font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;" + field_width = 120 + + # Support Condition section + support_title = QLabel("Support Condition*") + support_title.setStyleSheet(heading_style) + card_layout.addWidget(support_title) + + support_grid = QGridLayout() + support_grid.setContentsMargins(0, 8, 0, 0) + support_grid.setHorizontalSpacing(12) + support_grid.setVerticalSpacing(12) + support_grid.setColumnMinimumWidth(0, 120) + + # Left Support + lbl = QLabel("Left Support:") + lbl.setStyleSheet(label_style) + self.left_support_combo = QComboBox() + self.left_support_combo.addItems(["Fixed", "Pinned", "Roller"]) + self.left_support_combo.setFixedWidth(field_width) + apply_field_style(self.left_support_combo) + support_grid.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + support_grid.addWidget(self.left_support_combo, 0, 1, Qt.AlignLeft) + + # Right Support + lbl = QLabel("Right Support:") + lbl.setStyleSheet(label_style) + self.right_support_combo = QComboBox() + self.right_support_combo.addItems(["Fixed", "Pinned", "Roller"]) + self.right_support_combo.setFixedWidth(field_width) + apply_field_style(self.right_support_combo) + support_grid.addWidget(lbl, 1, 0, Qt.AlignLeft | Qt.AlignVCenter) + support_grid.addWidget(self.right_support_combo, 1, 1, Qt.AlignLeft) + + card_layout.addLayout(support_grid) + + # Bearing Length section + bearing_title = QLabel("Bearing length*") + bearing_title.setStyleSheet(heading_style) + card_layout.addWidget(bearing_title) + + bearing_grid = QGridLayout() + bearing_grid.setContentsMargins(0, 8, 0, 0) + bearing_grid.setHorizontalSpacing(12) + bearing_grid.setVerticalSpacing(12) + bearing_grid.setColumnMinimumWidth(0, 120) + + lbl = QLabel("Bearing Length Value") + lbl.setStyleSheet(label_style) + self.bearing_length_input = QLineEdit() + self.bearing_length_input.setText("0") + self.bearing_length_input.setFixedWidth(field_width) + apply_field_style(self.bearing_length_input) + bearing_grid.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + bearing_grid.addWidget(self.bearing_length_input, 0, 1, Qt.AlignLeft) + + card_layout.addLayout(bearing_grid) + card_layout.addStretch() + + main_layout.addWidget(card) + main_layout.addStretch() + + return widget + + def _build_design_options_tab(self): + """Build the Design Options tab matching reference design""" + widget = QWidget() + widget.setStyleSheet("background-color: #f5f5f5;") + + main_layout = QVBoxLayout(widget) + main_layout.setContentsMargins(12, 12, 12, 12) + main_layout.setSpacing(12) + + # Main card + card = QFrame() + card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + card_layout = QVBoxLayout(card) + card_layout.setContentsMargins(16, 16, 16, 16) + card_layout.setSpacing(12) + + label_style = "font-size: 11px; color: #3a3a3a; background: transparent; border: none;" + heading_style = "font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;" + field_width = 120 + + # Deck Design section + deck_title = QLabel("Deck Design:") + deck_title.setStyleSheet(heading_style) + card_layout.addWidget(deck_title) + + deck_grid = QGridLayout() + deck_grid.setContentsMargins(0, 4, 0, 0) + deck_grid.setHorizontalSpacing(12) + deck_grid.setVerticalSpacing(10) + deck_grid.setColumnMinimumWidth(0, 120) + + lbl = QLabel("Reinforcement Size:") + lbl.setStyleSheet(label_style) + self.reinforcement_size_combo = QComboBox() + self.reinforcement_size_combo.addItems(["8 mm", "10 mm", "12 mm", "16 mm", "20 mm"]) + self.reinforcement_size_combo.setFixedWidth(field_width) + apply_field_style(self.reinforcement_size_combo) + deck_grid.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + deck_grid.addWidget(self.reinforcement_size_combo, 0, 1, Qt.AlignLeft) + + card_layout.addLayout(deck_grid) + + # Shear Studs section + shear_title = QLabel("Shear Studs:") + shear_title.setStyleSheet(heading_style) + card_layout.addWidget(shear_title) + + shear_grid = QGridLayout() + shear_grid.setContentsMargins(0, 4, 0, 0) + shear_grid.setHorizontalSpacing(12) + shear_grid.setVerticalSpacing(10) + shear_grid.setColumnMinimumWidth(0, 120) + + # Material + lbl = QLabel("Material:") + lbl.setStyleSheet(label_style) + self.shear_stud_material_input = QLineEdit() + self.shear_stud_material_input.setFixedWidth(field_width) + apply_field_style(self.shear_stud_material_input) + shear_grid.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + shear_grid.addWidget(self.shear_stud_material_input, 0, 1, Qt.AlignLeft) + + # Diameter + lbl = QLabel("Diameter (mm):") + lbl.setStyleSheet(label_style) + self.shear_stud_diameter_input = QLineEdit() + self.shear_stud_diameter_input.setFixedWidth(field_width) + apply_field_style(self.shear_stud_diameter_input) + shear_grid.addWidget(lbl, 1, 0, Qt.AlignLeft | Qt.AlignVCenter) + shear_grid.addWidget(self.shear_stud_diameter_input, 1, 1, Qt.AlignLeft) + + # Height + lbl = QLabel("Height (mm):") + lbl.setStyleSheet(label_style) + self.shear_stud_height_input = QLineEdit() + self.shear_stud_height_input.setFixedWidth(field_width) + apply_field_style(self.shear_stud_height_input) + shear_grid.addWidget(lbl, 2, 0, Qt.AlignLeft | Qt.AlignVCenter) + shear_grid.addWidget(self.shear_stud_height_input, 2, 1, Qt.AlignLeft) + + card_layout.addLayout(shear_grid) + card_layout.addStretch() + + main_layout.addWidget(card) + main_layout.addStretch() + + return widget + + def create_placeholder_tab(self, title, description): + """Create a styled placeholder tab with title and description""" + widget = QWidget() + widget.setStyleSheet("background-color: white;") + + layout = QVBoxLayout(widget) + layout.setAlignment(Qt.AlignCenter) + layout.setContentsMargins(40, 40, 40, 40) + + # Icon or visual indicator + icon_label = QLabel("🚧") + icon_label.setStyleSheet("font-size: 48px;") + icon_label.setAlignment(Qt.AlignCenter) + layout.addWidget(icon_label) + + # Title + title_label = QLabel(title) + title_label.setStyleSheet(""" + font-size: 18px; + font-weight: bold; + color: #333; + margin-top: 20px; + margin-bottom: 10px; + """) + title_label.setAlignment(Qt.AlignCenter) + layout.addWidget(title_label) + + # Status + status_label = QLabel("Under Development") + status_label.setStyleSheet(""" + font-size: 14px; + color: #f39c12; + font-weight: bold; + margin-bottom: 20px; + """) + status_label.setAlignment(Qt.AlignCenter) + layout.addWidget(status_label) + + # Description + desc_label = QLabel(description) + desc_label.setStyleSheet(""" + font-size: 12px; + color: #666; + line-height: 1.6; + """) + desc_label.setAlignment(Qt.AlignCenter) + desc_label.setWordWrap(True) + desc_label.setMaximumWidth(600) + layout.addWidget(desc_label) + + layout.addStretch() + + return widget + + def update_footpath_value(self, footpath_value): + """Update footpath value across all tabs""" + self.footpath_value = footpath_value + self.typical_section_tab.update_footpath_value(footpath_value) + +# ================================================================================= +# SUB COMPONENTS +# ================================================================================= + +class TypicalSectionDetailsTab(QWidget): + """Sub-tab for Typical Section Details inputs""" + + footpath_changed = Signal(str) + + def __init__(self, footpath_value="None", carriageway_width=7.5, parent=None): + super().__init__(parent) + self.footpath_value = footpath_value + self.carriageway_width = carriageway_width + self.updating_fields = False + self.init_ui() + + def style_input_field(self, field): + apply_field_style(field) + + def style_group_box(self, group_box): + group_box.setStyleSheet(""" + QGroupBox { + font-weight: bold; + border: 2px solid #d0d0d0; + border-radius: 6px; + margin-top: 12px; + padding-top: 15px; + background-color: #f9f9f9; + } + QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 10px; + padding: 0 5px; + background-color: white; + color: #4a7ba7; + } + """) + + def _create_section_card(self, title): + card = QFrame() + card.setObjectName("sectionCard") + card.setStyleSheet(""" + QFrame#sectionCard { + background-color: #f5f5f5; + border: none; + } + """) + card_layout = QVBoxLayout(card) + card_layout.setContentsMargins(0, 0, 0, 0) + card_layout.setSpacing(12) + + title_label = QLabel(title) + title_label.setStyleSheet("font-size: 12px; font-weight: bold; color: #000;") + card_layout.addWidget(title_label) + + return card, card_layout + + def init_ui(self): + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(10, 10, 10, 10) + main_layout.setSpacing(0) + + diagram_widget = QWidget() + diagram_widget.setStyleSheet(""" + QWidget { + background: transparent; + border: 1px solid #b0b0b0; + border-radius: 8px; + } + """) + diagram_widget.setMinimumHeight(150) + diagram_widget.setMaximumHeight(200) + diagram_layout = QVBoxLayout(diagram_widget) + diagram_layout.setContentsMargins(20, 20, 20, 20) + diagram_layout.setAlignment(Qt.AlignCenter) + + diagram_label = QLabel("Typical Section Details\nDiagram") + diagram_label.setAlignment(Qt.AlignCenter) + diagram_label.setStyleSheet(""" + QLabel { + background-color: transparent; + border: none; + padding: 20px; + font-size: 13px; + color: #333; + } + """) + diagram_layout.addWidget(diagram_label) + + main_layout.addWidget(diagram_widget) + main_layout.addSpacing(10) + + input_container = QWidget() + input_container.setStyleSheet("QWidget { background-color: white; }") + input_layout = QVBoxLayout(input_container) + input_layout.setContentsMargins(0, 0, 0, 0) + input_layout.setSpacing(0) + + self.input_tabs = QTabWidget() + self.input_tabs.setStyleSheet(""" + QTabWidget::pane { + border: 1px solid #b0b0b0; + border-top: none; + background-color: #f5f5f5; + border-radius: 0px 0px 8px 8px; + } + QTabBar::tab { + background-color: #e8e8e8; + color: #555; + padding: 10px 20px; + border: 1px solid #b0b0b0; + border-bottom: none; + border-right: none; + font-size: 11px; + min-width: 80px; + } + QTabBar::tab:last { + border-right: 1px solid #b0b0b0; + } + QTabBar::tab:selected { + background-color: #90AF13; + color: white; + font-weight: bold; + border: 1px solid #90AF13; + border-bottom: none; + } + QTabBar::tab:hover:!selected { + background-color: #d0d0d0; + } + """) + + self.create_layout_tab() + self.create_crash_barrier_tab() + self.create_median_tab() + self.create_railing_tab() + self.create_wearing_course_tab() + self.create_lane_details_tab() + + input_layout.addWidget(self.input_tabs) + main_layout.addWidget(input_container) + + self.deck_thickness.textChanged.connect(self.update_footpath_thickness) + self.recalculate_girders() + + def create_layout_tab(self): + layout_widget = QWidget() + layout_widget.setStyleSheet("background-color: #f5f5f5;") + layout_layout = QVBoxLayout(layout_widget) + layout_layout.setContentsMargins(18, 6, 18, 12) + layout_layout.setSpacing(0) + + title_label = QLabel("Inputs:") + title_label.setStyleSheet("font-size: 12px; font-weight: bold; color: #000;") + layout_layout.addWidget(title_label) + layout_layout.addSpacing(8) + + grid = QGridLayout() + grid.setHorizontalSpacing(24) + grid.setVerticalSpacing(10) + grid.setColumnStretch(1, 1) + grid.setColumnStretch(3, 1) + grid.setContentsMargins(0, 0, 0, 0) + + def _label(text): + lbl = QLabel(text) + lbl.setStyleSheet("font-size: 11px; color: #000;") + lbl.setMinimumWidth(180) + return lbl + + self.girder_spacing = QLineEdit() + self.girder_spacing.setValidator(QDoubleValidator(0.01, 50.0, 3)) + self.girder_spacing.setText(str(DEFAULT_GIRDER_SPACING)) + self.style_input_field(self.girder_spacing) + self.girder_spacing.textChanged.connect(self.on_girder_spacing_changed) + + self.no_of_girders = QLineEdit() + self.no_of_girders.setValidator(QIntValidator(2, 100)) + self.style_input_field(self.no_of_girders) + self.no_of_girders.textChanged.connect(self.on_no_of_girders_changed) + + grid.addWidget(_label("Girder Spacing (m):"), 0, 0, Qt.AlignLeft) + grid.addWidget(self.girder_spacing, 0, 1) + grid.addWidget(_label("No. of Girders:"), 0, 2, Qt.AlignLeft) + grid.addWidget(self.no_of_girders, 0, 3) + + self.deck_overhang = QLineEdit() + self.deck_overhang.setValidator(QDoubleValidator(0.0, 10.0, 3)) + self.deck_overhang.setText(str(DEFAULT_DECK_OVERHANG)) + self.style_input_field(self.deck_overhang) + self.deck_overhang.textChanged.connect(self.on_deck_overhang_changed) + + values_adjusted_label = QLabel("Values adjusted for:") + values_adjusted_label.setStyleSheet("font-size: 11px; color: #5b5b5b; font-style: italic;") + + grid.addWidget(_label("Deck Overhang Width (m):"), 1, 0, Qt.AlignLeft) + grid.addWidget(self.deck_overhang, 1, 1) + #grid.addWidget(values_adjusted_label, 1, 2, 1, 2, Qt.AlignLeft) + + self.overall_bridge_width_display = QLineEdit() + self.style_input_field(self.overall_bridge_width_display) + self.overall_bridge_width_display.setReadOnly(True) + self.overall_bridge_width_display.setEnabled(False) + + grid.addWidget(_label("Overall Bridge Width (m):"), 2, 0, Qt.AlignLeft) + grid.addWidget(self.overall_bridge_width_display, 2, 1) + + self.deck_thickness = QLineEdit() + self.deck_thickness.setValidator(QDoubleValidator(0.0, 500.0, 0)) + self.style_input_field(self.deck_thickness) + + self.footpath_thickness = QLineEdit() + self.footpath_thickness.setValidator(QDoubleValidator(0.0, 500.0, 0)) + self.style_input_field(self.footpath_thickness) + + grid.addWidget(_label("Deck Thickness (mm):"), 3, 0, Qt.AlignLeft) + grid.addWidget(self.deck_thickness, 3, 1) + grid.addWidget(_label("Footpath Thickness (mm):"), 4, 2, Qt.AlignLeft) + grid.addWidget(self.footpath_thickness, 4, 3) + + self.footpath_width = QLineEdit() + self.footpath_width.setValidator(QDoubleValidator(MIN_FOOTPATH_WIDTH, 5.0, 3)) + self.footpath_width.textChanged.connect(self.on_footpath_width_changed) + self.style_input_field(self.footpath_width) + self.footpath_width.setText(f"{MIN_FOOTPATH_WIDTH:.2f}") + + grid.addWidget(_label("Footpath Width (m):"), 4, 0, Qt.AlignLeft) + grid.addWidget(self.footpath_width, 4, 1) + + layout_layout.addLayout(grid) + # CHANGED: Add stretch at bottom to push content up + layout_layout.addStretch() + + self.input_tabs.addTab(layout_widget, "Layout") + def create_crash_barrier_tab(self): + crash_widget = QWidget() + crash_widget.setStyleSheet("background-color: #f5f5f5;") + crash_layout = QVBoxLayout(crash_widget) + crash_layout.setContentsMargins(18, 6, 18, 12) + crash_layout.setSpacing(0) + + card, card_layout = self._create_section_card("Crash Barrier Inputs:") + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(24) + grid.setVerticalSpacing(10) + grid.setColumnStretch(1, 1) + + def add_row(row, label_text, widget): + label = QLabel(label_text) + label.setStyleSheet("font-size: 11px; color: #000;") + label.setMinimumWidth(210) + grid.addWidget(label, row, 0, Qt.AlignLeft) + grid.addWidget(widget, row, 1) + + self.crash_barrier_type = QComboBox() + self.crash_barrier_type.addItems(VALUES_CRASH_BARRIER_TYPE) + self.style_input_field(self.crash_barrier_type) + self.crash_barrier_type.currentTextChanged.connect(self.on_crash_barrier_type_changed) + add_row(0, "Type:", self.crash_barrier_type) + + self.crash_barrier_density = QLineEdit() + self.crash_barrier_density.setValidator(QDoubleValidator(0.0, 100.0, 2)) + self.style_input_field(self.crash_barrier_density) + add_row(1, "Material Density (kN/m^3):", self.crash_barrier_density) + + self.crash_barrier_width = QLineEdit() + self.crash_barrier_width.setValidator(QDoubleValidator(0.0, 2.0, 3)) + self.crash_barrier_width.setText(str(DEFAULT_CRASH_BARRIER_WIDTH)) + self.style_input_field(self.crash_barrier_width) + self.crash_barrier_width.textChanged.connect(self.recalculate_girders) + add_row(2, "Width (m):", self.crash_barrier_width) + + self.crash_barrier_height = QLineEdit() + self.crash_barrier_height.setValidator(QDoubleValidator(0.0, 3.0, 3)) + self.style_input_field(self.crash_barrier_height) + add_row(3, "Height (m):", self.crash_barrier_height) + + self.crash_barrier_area = QLineEdit() + self.crash_barrier_area.setValidator(QDoubleValidator(0.0, 10.0, 4)) + self.style_input_field(self.crash_barrier_area) + add_row(4, "Area (m^2):", self.crash_barrier_area) + + card_layout.addLayout(grid) + crash_layout.addWidget(card) + crash_layout.addStretch() + self.input_tabs.addTab(crash_widget, "Crash Barrier") + + def create_median_tab(self): + median_widget = QWidget() + median_widget.setStyleSheet("background-color: #f5f5f5;") + median_layout = QVBoxLayout(median_widget) + median_layout.setContentsMargins(18, 6, 18, 12) + median_layout.setSpacing(0) + + card, card_layout = self._create_section_card("Median Inputs:") + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(24) + grid.setVerticalSpacing(10) + grid.setColumnStretch(1, 1) + + def add_row(row, label_text, widget): + label = QLabel(label_text) + label.setStyleSheet("font-size: 11px; color: #000;") + label.setMinimumWidth(210) + grid.addWidget(label, row, 0, Qt.AlignLeft) + grid.addWidget(widget, row, 1) + + self.median_type = QComboBox() + self.median_type.addItems(VALUES_MEDIAN_TYPE) + self.style_input_field(self.median_type) + add_row(0, "Type:", self.median_type) + + self.median_density = QLineEdit() + self.median_density.setValidator(QDoubleValidator(0.0, 100.0, 2)) + self.style_input_field(self.median_density) + add_row(1, "Material Density (kN/m^3):", self.median_density) + + self.median_width = QLineEdit() + self.median_width.setValidator(QDoubleValidator(0.0, 3.0, 3)) + self.style_input_field(self.median_width) + add_row(2, "Width (m):", self.median_width) + + self.median_height = QLineEdit() + self.median_height.setValidator(QDoubleValidator(0.0, 3.0, 3)) + self.style_input_field(self.median_height) + add_row(3, "Height (m):", self.median_height) + + self.median_area = QLineEdit() + self.median_area.setValidator(QDoubleValidator(0.0, 10.0, 4)) + self.style_input_field(self.median_area) + add_row(4, "Area (m^2):", self.median_area) + + card_layout.addLayout(grid) + median_layout.addWidget(card) + median_layout.addStretch() + self.input_tabs.addTab(median_widget, "Median") + + def create_railing_tab(self): + railing_widget = QWidget() + railing_widget.setStyleSheet("background-color: #f5f5f5;") + railing_layout = QVBoxLayout(railing_widget) + railing_layout.setContentsMargins(18, 6, 18, 12) + railing_layout.setSpacing(0) + + card, card_layout = self._create_section_card("Railing Inputs:") + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(24) + grid.setVerticalSpacing(10) + grid.setColumnStretch(1, 1) + + def add_row(row, label_text, widget): + label = QLabel(label_text) + label.setStyleSheet("font-size: 11px; color: #000;") + label.setMinimumWidth(180) + grid.addWidget(label, row, 0, Qt.AlignLeft) + grid.addWidget(widget, row, 1) + + self.railing_type = QComboBox() + self.railing_type.addItems(VALUES_RAILING_TYPE) + self.style_input_field(self.railing_type) + add_row(0, "Type:", self.railing_type) + + self.railing_width = QLineEdit() + self.railing_width.setValidator(QDoubleValidator(0.0, 2000.0, 1)) + self.railing_width.setText(f"{DEFAULT_RAILING_WIDTH * 1000:.0f}") + self.style_input_field(self.railing_width) + self.railing_width.textChanged.connect(self.recalculate_girders) + add_row(1, "Width (mm):", self.railing_width) + + self.railing_height = QLineEdit() + self.railing_height.setValidator(QDoubleValidator(MIN_RAILING_HEIGHT, 3.0, 3)) + self.style_input_field(self.railing_height) + self.railing_height.editingFinished.connect(self.validate_railing_height) + add_row(2, "Height (m):", self.railing_height) + + load_row = QHBoxLayout() + load_row.setContentsMargins(0, 0, 0, 0) + load_row.setSpacing(12) + + self.railing_load_mode = QComboBox() + self.railing_load_mode.addItems(["Automatic (IRC 6)", "User-defined"]) + self.style_input_field(self.railing_load_mode) + self.railing_load_mode.currentTextChanged.connect(self.on_railing_load_mode_changed) + load_row.addWidget(self.railing_load_mode) + + self.railing_load_value = QLineEdit() + self.railing_load_value.setValidator(QDoubleValidator(0.0, 50.0, 2)) + self.railing_load_value.setPlaceholderText("Value") + self.railing_load_value.setEnabled(False) + self.style_input_field(self.railing_load_value) + load_row.addWidget(self.railing_load_value) + + load_container = QWidget() + load_container.setLayout(load_row) + add_row(3, "Load (kN/m):", load_container) + + card_layout.addLayout(grid) + railing_layout.addWidget(card) + railing_layout.addStretch() + self.input_tabs.addTab(railing_widget, "Railing") + + def create_wearing_course_tab(self): + wearing_widget = QWidget() + wearing_widget.setStyleSheet("background-color: #f5f5f5;") + wearing_layout = QVBoxLayout(wearing_widget) + wearing_layout.setContentsMargins(18, 6, 18, 12) + wearing_layout.setSpacing(0) + + card, card_layout = self._create_section_card("Wearing Course Inputs:") + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(24) + grid.setVerticalSpacing(10) + grid.setColumnStretch(1, 1) + + def add_row(row, label_text, widget): + label = QLabel(label_text) + label.setStyleSheet("font-size: 11px; color: #000;") + label.setMinimumWidth(200) + grid.addWidget(label, row, 0, Qt.AlignLeft) + grid.addWidget(widget, row, 1) + + self.wearing_material = QComboBox() + self.wearing_material.addItems(VALUES_WEARING_COAT_MATERIAL) + self.style_input_field(self.wearing_material) + add_row(0, "Material:", self.wearing_material) + + self.wearing_density = QLineEdit() + self.wearing_density.setValidator(QDoubleValidator(0.0, 40.0, 2)) + self.style_input_field(self.wearing_density) + add_row(1, "Density (kN/m^3):", self.wearing_density) + + self.wearing_thickness = QLineEdit() + self.wearing_thickness.setValidator(QDoubleValidator(0.0, 200.0, 1)) + self.style_input_field(self.wearing_thickness) + add_row(2, "Thickness (mm):", self.wearing_thickness) + + card_layout.addLayout(grid) + wearing_layout.addWidget(card) + wearing_layout.addStretch() + self.input_tabs.addTab(wearing_widget, "Wearing Course") + + def create_lane_details_tab(self): + lane_widget = QWidget() + lane_widget.setStyleSheet("background-color: #f5f5f5;") + lane_layout = QVBoxLayout(lane_widget) + lane_layout.setContentsMargins(18, 6, 18, 12) + lane_layout.setSpacing(0) + + card, card_layout = self._create_section_card("Inputs:") + + selector_layout = QHBoxLayout() + selector_layout.setContentsMargins(0, 0, 0, 0) + selector_layout.setSpacing(12) + + lanes_label = QLabel("No. of Traffic Lanes:") + lanes_label.setStyleSheet("font-size: 11px; color: #000;") + selector_layout.addWidget(lanes_label) + + self.lane_count_combo = QComboBox() + self.lane_count_combo.addItems([str(i) for i in range(1, 7)]) + self.style_input_field(self.lane_count_combo) + self.lane_count_combo.currentTextChanged.connect(self.on_lane_count_changed) + selector_layout.addWidget(self.lane_count_combo) + selector_layout.addStretch() + + card_layout.addLayout(selector_layout) + + self.lane_table = QTableWidget() + self.lane_table.setColumnCount(3) + self.lane_table.setHorizontalHeaderLabels([ + "Traffic Lane Number", + "Distance from inner edge of crash barrier to left edge of lane (m)", + "Lane Width (m)" + ]) + header = self.lane_table.horizontalHeader() + header.setSectionResizeMode(0, QHeaderView.ResizeToContents) + header.setSectionResizeMode(1, QHeaderView.Stretch) + header.setSectionResizeMode(2, QHeaderView.ResizeToContents) + self.lane_table.verticalHeader().setVisible(False) + self.lane_table.setAlternatingRowColors(True) + self.lane_table.setStyleSheet(""" + QTableWidget { + background-color: #ffffff; + alternate-background-color: #f9f9f9; + gridline-color: #e0e0e0; + border: 1px solid #e0e0e0; + } + QTableWidget::item { + padding: 8px; + border-bottom: 1px solid #e0e0e0; + } + QTableWidget::item:hover { + background-color: #e8f4f8; + } + QHeaderView::section { + background-color: #f5f5f5; + color: #333; + padding: 8px; + border: 1px solid #e0e0e0; + font-weight: bold; + font-size: 11px; + } + """) + + card_layout.addWidget(self.lane_table) + lane_layout.addWidget(card) + lane_layout.addStretch() + + self.input_tabs.addTab(lane_widget, "Lane Details") + self._update_lane_details_rows(self.lane_count_combo.currentText()) + + def _update_lane_details_rows(self, count): + try: + num_lanes = int(count) + self.lane_table.setRowCount(num_lanes) + + for i in range(num_lanes): + # Lane number (non-editable) + lane_num_item = QTableWidgetItem(str(i + 1)) + lane_num_item.setFlags(lane_num_item.flags() & ~Qt.ItemIsEditable) + lane_num_item.setTextAlignment(Qt.AlignCenter) + self.lane_table.setItem(i, 0, lane_num_item) + + # Distance field (editable) + if not self.lane_table.item(i, 1): + self.lane_table.setItem(i, 1, QTableWidgetItem("")) + + # Width field (editable) + if not self.lane_table.item(i, 2): + self.lane_table.setItem(i, 2, QTableWidgetItem("")) + except ValueError: + pass + + def update_footpath_value(self, footpath_value): + self.footpath_value = footpath_value + if hasattr(self, "footpath_width"): + self.footpath_width.setEnabled(footpath_value != "None") + self.footpath_thickness.setEnabled(footpath_value != "None") + self.recalculate_girders() + self.footpath_changed.emit(footpath_value) + + def get_overall_bridge_width(self): + try: + overall_width = self.carriageway_width + if self.footpath_value != "None": + footpath_width = float(self.footpath_width.text()) if self.footpath_width.text() else 0 + num_footpaths = 2 if self.footpath_value == "Both" else (1 if self.footpath_value == "Single Sided" else 0) + overall_width += footpath_width * num_footpaths + + crash_barrier_width = float(self.crash_barrier_width.text()) if self.crash_barrier_width.text() else DEFAULT_CRASH_BARRIER_WIDTH + overall_width += crash_barrier_width * 2 + + if self.footpath_value != "None": + railing_width_text = self.railing_width.text() if hasattr(self, "railing_width") else "" + if railing_width_text: + railing_width = float(railing_width_text) / 1000.0 + else: + railing_width = DEFAULT_RAILING_WIDTH + overall_width += railing_width * 2 + + return overall_width + except: + return self.carriageway_width + + def _update_overall_bridge_width_display(self): + if hasattr(self, "overall_bridge_width_display"): + try: + overall_width = self.get_overall_bridge_width() + self.overall_bridge_width_display.setText(f"{overall_width:.3f}") + except: + self.overall_bridge_width_display.clear() + + def recalculate_girders(self): + if self.updating_fields: + return + try: + self._update_overall_bridge_width_display() + overall_width = self.get_overall_bridge_width() + spacing = float(self.girder_spacing.text()) if self.girder_spacing.text() else DEFAULT_GIRDER_SPACING + overhang = float(self.deck_overhang.text()) if self.deck_overhang.text() else DEFAULT_DECK_OVERHANG + if spacing >= overall_width or overhang >= overall_width: + self.no_of_girders.setText("") + return + if spacing > 0: + no_girders = int(round((overall_width - 2 * overhang) / spacing)) + 1 + if no_girders >= 2: + self.updating_fields = True + self.no_of_girders.setText(str(no_girders)) + self.updating_fields = False + except: + pass + + def on_girder_spacing_changed(self): + if not self.updating_fields: + try: + overall_width = self.get_overall_bridge_width() + spacing_text = self.girder_spacing.text() + if spacing_text: + spacing = float(spacing_text) + if spacing >= overall_width: + QMessageBox.warning(self, "Invalid Girder Spacing", + f"Girder spacing ({spacing:.2f} m) must be less than overall bridge width ({overall_width:.2f} m).") + return + self.recalculate_girders() + except: + pass + + def on_deck_overhang_changed(self): + if not self.updating_fields: + try: + overall_width = self.get_overall_bridge_width() + overhang_text = self.deck_overhang.text() + if overhang_text: + overhang = float(overhang_text) + if overhang >= overall_width: + QMessageBox.warning(self, "Invalid Deck Overhang", + f"Deck overhang ({overhang:.2f} m) must be less than overall bridge width ({overall_width:.2f} m).") + return + self.recalculate_girders() + except: + pass + + def on_no_of_girders_changed(self): + if not self.updating_fields: + try: + no_girders_text = self.no_of_girders.text() + if no_girders_text: + no_girders = int(no_girders_text) + if no_girders < 2: + QMessageBox.warning(self, "Invalid Number of Girders", + "Number of girders must be at least 2.") + return + overall_width = self.get_overall_bridge_width() + overhang = float(self.deck_overhang.text()) if self.deck_overhang.text() else DEFAULT_DECK_OVERHANG + if no_girders > 1: + new_spacing = (overall_width - 2 * overhang) / (no_girders - 1) + self.updating_fields = True + self.girder_spacing.setText(f"{new_spacing:.3f}") + self.updating_fields = False + except: + pass + + def on_footpath_width_changed(self): + if not self.updating_fields: + self.recalculate_girders() + + def validate_footpath_width(self): + try: + if self.footpath_width.text(): + width = float(self.footpath_width.text()) + if width < MIN_FOOTPATH_WIDTH: + QMessageBox.critical(self, "Footpath Width Error", + f"Footpath width must be at least {MIN_FOOTPATH_WIDTH} m as per IRC 5 Clause 104.3.6.") + except: + pass + + def validate_railing_height(self): + try: + if self.railing_height.text(): + height = float(self.railing_height.text()) + if height < MIN_RAILING_HEIGHT: + QMessageBox.critical(self, "Railing Height Error", + f"Railing height must be at least {MIN_RAILING_HEIGHT} m as per IRC 5 Clauses 109.7.2.3 and 109.7.2.4.") + except: + pass + + def update_footpath_thickness(self): + if self.deck_thickness.text() and not self.footpath_thickness.text(): + self.footpath_thickness.setText(self.deck_thickness.text()) + + def on_crash_barrier_type_changed(self, barrier_type): + if (barrier_type in ["Flexible", "Semi-Rigid"]) and (self.footpath_value == "None"): + QMessageBox.critical(self, "Crash Barrier Type Not Permitted", + f"{barrier_type} crash barriers are not permitted on bridges without an outer footpath per IRC 5 Clause 109.6.4.") + + def on_railing_load_mode_changed(self, mode): + if not hasattr(self, "railing_load_value"): + return + is_auto = mode.startswith("Automatic") + self.railing_load_value.setEnabled(not is_auto) + if is_auto: + self.railing_load_value.clear() + + def on_lane_count_changed(self, text): + self._update_lane_details_rows(text) + + def _update_lane_details_rows(self, count): + try: + total_rows = int(count) + except (TypeError, ValueError): + total_rows = 1 + if not hasattr(self, "lane_table"): + return + self.lane_table.setRowCount(total_rows) + for row in range(total_rows): + lane_item = QTableWidgetItem(str(row + 1)) + lane_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) + self.lane_table.setItem(row, 0, lane_item) + for col in range(1, self.lane_table.columnCount()): + existing_item = self.lane_table.item(row, col) + if existing_item is None: + self.lane_table.setItem(row, col, QTableWidgetItem("")) + + def _show_placeholder_message(self, action_name): + QMessageBox.information(self, action_name, "This action will be available in an upcoming update.") + +class OptimizableField(QWidget): + """Widget that allows selection between Optimized/Customized/All modes with input field""" + + def __init__(self, label_text, parent=None): + super().__init__(parent) + self.layout = QHBoxLayout(self) + self.layout.setContentsMargins(0, 0, 0, 0) + self.layout.setSpacing(8) + + self.mode_combo = QComboBox() + self.mode_combo.addItems(VALUES_OPTIMIZATION_MODE) + self.mode_combo.setMinimumWidth(140) + self.mode_combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + + self.input_field = QLineEdit() + self.input_field.setEnabled(False) + self.input_field.setVisible(False) + self.input_field.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + + self.layout.addWidget(self.mode_combo) + self.layout.addWidget(self.input_field) + + self.mode_combo.currentTextChanged.connect(self.on_mode_changed) + self.on_mode_changed(self.mode_combo.currentText()) + + def on_mode_changed(self, text): + """Enable/disable input field based on selection""" + if text in ("Optimized", "All", "NA"): + self.input_field.setEnabled(False) + self.input_field.clear() + self.input_field.setVisible(False) + else: + self.input_field.setEnabled(True) + self.input_field.setVisible(True) + + def get_value(self): + """Returns tuple of (mode, value)""" + return (self.mode_combo.currentText(), self.input_field.text()) + +class SectionPropertiesTab(QWidget): + """Sub-tab for Section Properties with custom navigation layout.""" + + def __init__(self, parent=None): + super().__init__(parent) + self.nav_buttons = [] + self.section_widgets = [] + self.girder_tab = None + self.init_ui() + + def init_ui(self): + """Initialize styled navigation and content panels.""" + self.setStyleSheet("background-color: #f0f0f0;") + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(10, 10, 10, 10) + main_layout.setSpacing(10) + + # Top navigation bar (horizontal) + nav_bar = QWidget() + nav_bar.setStyleSheet("background-color: white;") + nav_bar_layout = QHBoxLayout(nav_bar) + nav_bar_layout.setContentsMargins(6, 0, 6, 0) + nav_bar_layout.setSpacing(5) + + main_layout.addWidget(nav_bar) + + # Content frame + content_frame = QFrame() + content_frame.setObjectName("sectionContentFrame") + content_frame.setStyleSheet(""" + QFrame#sectionContentFrame { + background-color: #f0f0f0; + border: none; + } + """) + content_inner_layout = QVBoxLayout(content_frame) + content_inner_layout.setContentsMargins(0, 0, 0, 0) + content_inner_layout.setSpacing(0) + + self.stack = QStackedWidget() + self.stack.setObjectName("sectionStack") + self.stack.setStyleSheet("QStackedWidget#sectionStack { background-color: transparent; }") + content_inner_layout.addWidget(self.stack) + + main_layout.addWidget(content_frame, 1) + + sections = [ + ("Girder Details:", GirderDetailsTab), + ("Stiffener Details:", StiffenerDetailsTab), + ("Cross-Bracing Details:", CrossBracingDetailsTab), + ("End Diaphragm Details:", EndDiaphragmDetailsTab), + ] + + for i, (label, widget_class) in enumerate(sections): + btn = QPushButton(label) + btn.setObjectName("sectionNavBtn") + btn.setCheckable(True) + btn.setStyleSheet(""" + QPushButton#sectionNavBtn { + background-color: white; + color: #333; + border: 1px solid #b0b0b0; + border-right: none; + padding: 3px 10px; + text-align: center; + font-size: 10px; + font-weight: normal; + min-height: 26px; + } + QPushButton#sectionNavBtn:first { + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + QPushButton#sectionNavBtn:last { + border-right: 1px solid #b0b0b0; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + } + QPushButton#sectionNavBtn:checked { + background-color: #90AF13; + color: white; + font-weight: bold; + border: 1px solid #90AF13; + } + QPushButton#sectionNavBtn:hover:!checked { + background-color: #f5f5f5; + } + """) + btn.clicked.connect(lambda checked, idx=i: self.switch_section(idx)) + self.nav_buttons.append(btn) + nav_bar_layout.addWidget(btn) + + section_widget = widget_class() + if isinstance(section_widget, GirderDetailsTab): + self.girder_tab = section_widget + self.section_widgets.append(section_widget) + self.stack.addWidget(section_widget) + + if self.nav_buttons: + self.nav_buttons[0].setChecked(True) + self.stack.setCurrentIndex(0) + + def switch_section(self, index): + """Switch the stacked widget page and update navigation states.""" + self.stack.setCurrentIndex(index) + for btn_index, button in enumerate(self.nav_buttons): + button.setChecked(btn_index == index) + + +class GirderDetailsTab(QWidget): + """Tab for Girder Details styled to match the provided reference.""" + + def __init__(self, parent=None): + super().__init__(parent) + self.welded_rows = [] + self.rolled_rows = [] + self.symmetry_row = [] + self.web_type_row = [] + self.section_property_inputs = {} + self.segment_chain = {} + self._suppress_distance_updates = False + self.available_girders = [f"G{i}" for i in range(1, 6)] + self.init_ui() + + def init_ui(self): + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setStyleSheet("QScrollArea { border: none; background: transparent; }") + main_layout.addWidget(scroll) + + content = QWidget() + scroll.setWidget(content) + content.setStyleSheet("background-color: white;") + + content_layout = QVBoxLayout(content) + content_layout.setContentsMargins(10, 0, 10, 10) + content_layout.setSpacing(12) + + content_layout.addWidget(self._build_overview_card()) + content_layout.addWidget(self._build_section_card()) + content_layout.addStretch() + + def _build_overview_card(self): + card = self._create_card_frame() + layout = QGridLayout(card) + layout.setContentsMargins(18, 16, 18, 16) + layout.setHorizontalSpacing(20) + layout.setVerticalSpacing(12) + layout.setColumnStretch(1, 1) + layout.setColumnStretch(3, 1) + + self.select_girder_combo = CheckableComboBox() + self.select_girder_combo.addItems(["All"] + self.available_girders) + apply_field_style(self.select_girder_combo) + self._set_field_width(self.select_girder_combo) + layout.addWidget(self._create_label("Select Girder:"), 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + layout.addWidget(self.select_girder_combo, 0, 1, 1, 3) + + self.span_combo = QComboBox() + self.span_combo.addItems(VALUES_GIRDER_SPAN_MODE) + apply_field_style(self.span_combo) + self._set_field_width(self.span_combo) + self.span_combo.currentTextChanged.connect(self._on_span_changed) + layout.addWidget(self._create_label("Span:"), 1, 0, Qt.AlignLeft | Qt.AlignVCenter) + layout.addWidget(self.span_combo, 1, 1, Qt.AlignLeft) + + self.member_id_input = QLineEdit() + self.member_id_input.setPlaceholderText("G1-1") + apply_field_style(self.member_id_input) + self._set_field_width(self.member_id_input) + self.member_id_input.textChanged.connect(self._on_member_id_changed) + layout.addWidget(self._create_label("Member ID:"), 1, 2, Qt.AlignLeft | Qt.AlignVCenter) + layout.addWidget(self.member_id_input, 1, 3, Qt.AlignLeft) + + self.distance_start_input = QLineEdit("0") + self.distance_end_input = QLineEdit("30") + apply_field_style(self.distance_start_input) + apply_field_style(self.distance_end_input) + self._set_field_width(self.distance_start_input, 80) + self._set_field_width(self.distance_end_input, 80) + self.distance_start_input.editingFinished.connect(self._on_distance_start_changed) + self.distance_end_input.editingFinished.connect(self._on_distance_end_changed) + distance_row = self._build_distance_row() + layout.addWidget(self._create_label("Distance from left edge (m):"), 2, 0, Qt.AlignLeft | Qt.AlignTop) + layout.addLayout(distance_row, 2, 1, Qt.AlignLeft) + + self.length_input = QLineEdit("30") + apply_field_style(self.length_input) + self._set_field_width(self.length_input) + self.length_input.setReadOnly(True) + self.length_input.textChanged.connect(self._on_length_changed) + layout.addWidget(self._create_label("Length (m):"), 2, 2, Qt.AlignLeft | Qt.AlignVCenter) + layout.addWidget(self.length_input, 2, 3, Qt.AlignLeft) + + self._setup_girder_selector() + self._on_span_changed(self.span_combo.currentText()) + + return card + + def _build_distance_row(self): + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(16) + + def _build_column(line_edit, caption): + column = QVBoxLayout() + column.setContentsMargins(0, 0, 0, 0) + column.setSpacing(2) + column.addWidget(line_edit) + label = self._create_small_label(caption) + label.setAlignment(Qt.AlignCenter) + column.addWidget(label, alignment=Qt.AlignCenter) + return column + + row.addLayout(_build_column(self.distance_start_input, "Start")) + row.addLayout(_build_column(self.distance_end_input, "End")) + return row + + def _build_section_card(self): + container = QWidget() + container.setStyleSheet("background: transparent;") + main_layout = QHBoxLayout(container) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(16) + + # Left side - two bordered boxes stacked vertically + left_column = QWidget() + left_column.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + left_column_layout = QVBoxLayout(left_column) + left_column_layout.setContentsMargins(0, 0, 0, 0) + left_column_layout.setSpacing(12) + + # Section Inputs box (single frame containing all fields) + section_inputs_box = self._create_inner_box() + section_inputs_layout = QVBoxLayout(section_inputs_box) + section_inputs_layout.setContentsMargins(12, 8, 12, 12) + section_inputs_layout.setSpacing(8) + + section_inputs_title = self._create_label("Section Inputs:") + section_inputs_layout.addWidget(section_inputs_title) + + inputs_grid = QGridLayout() + inputs_grid.setContentsMargins(0, 0, 0, 0) + inputs_grid.setHorizontalSpacing(16) + inputs_grid.setVerticalSpacing(12) + inputs_grid.setColumnMinimumWidth(0, 150) + inputs_grid.setColumnStretch(0, 0) + inputs_grid.setColumnStretch(1, 1) + + self.design_combo = QComboBox() + self.design_combo.addItems(VALUES_GIRDER_DESIGN_MODE) + apply_field_style(self.design_combo) + row = self._add_box_row(inputs_grid, 0, "Design:", self.design_combo) + + self.type_combo = QComboBox() + self.type_combo.addItems(VALUES_GIRDER_TYPE) + apply_field_style(self.type_combo) + row = self._add_box_row(inputs_grid, row, "Type:", self.type_combo) + + self.symmetry_combo = QComboBox() + self.symmetry_combo.addItems(VALUES_GIRDER_SYMMETRY) + apply_field_style(self.symmetry_combo) + row = self._add_box_row(inputs_grid, row, "Symmetry:", self.symmetry_combo, self.symmetry_row) + + self.total_depth_input = self._create_line_edit() + row = self._add_box_row( + inputs_grid, + row, + "Total Depth (d, mm):", + self.total_depth_input, + self.welded_rows, + ) + + self.web_thickness_combo = QComboBox() + self.web_thickness_combo.addItems(VALUES_PROFILE_SCOPE) + apply_field_style(self.web_thickness_combo) + row = self._add_box_row( + inputs_grid, + row, + "Web Thickness (wt, mm):", + self.web_thickness_combo, + self.welded_rows, + ) + + self.top_width_input = self._create_line_edit() + row = self._add_box_row( + inputs_grid, + row, + "Width of Top Flange (tfw, mm):", + self.top_width_input, + self.welded_rows, + ) + + self.top_thickness_combo = QComboBox() + self.top_thickness_combo.addItems(VALUES_PROFILE_SCOPE) + apply_field_style(self.top_thickness_combo) + row = self._add_box_row( + inputs_grid, + row, + "Top Flange Thickness (tft, mm):", + self.top_thickness_combo, + self.welded_rows, + ) + + self.bottom_width_input = self._create_line_edit() + row = self._add_box_row( + inputs_grid, + row, + "Width of Bottom Flange (bfw, mm):", + self.bottom_width_input, + self.welded_rows, + ) + + self.bottom_thickness_combo = QComboBox() + self.bottom_thickness_combo.addItems(VALUES_PROFILE_SCOPE) + apply_field_style(self.bottom_thickness_combo) + row = self._add_box_row( + inputs_grid, + row, + "Bottom Flange Thickness (bft, mm):", + self.bottom_thickness_combo, + self.welded_rows, + ) + + self.is_section_combo = QComboBox() + self._populate_rolled_section_combo() + apply_field_style(self.is_section_combo) + self._add_box_row(inputs_grid, row, "IS Section:", self.is_section_combo, self.rolled_rows) + + section_inputs_layout.addLayout(inputs_grid) + left_column_layout.addWidget(section_inputs_box) + + # Restraint/Web details box + restraint_box = self._create_inner_box() + restraint_layout = QVBoxLayout(restraint_box) + restraint_layout.setContentsMargins(12, 6, 12, 10) + restraint_layout.setSpacing(6) + + restraint_title = self._create_label("Restraint & Web Details:") + restraint_layout.addWidget(restraint_title) + + restraint_grid = QGridLayout() + restraint_grid.setContentsMargins(0, 0, 0, 0) + restraint_grid.setHorizontalSpacing(16) + restraint_grid.setVerticalSpacing(12) + restraint_grid.setColumnMinimumWidth(0, 150) + restraint_grid.setColumnStretch(0, 0) + restraint_grid.setColumnStretch(1, 1) + + self.torsion_combo = QComboBox() + apply_field_style(self.torsion_combo) + row = self._add_box_row(restraint_grid, 0, "Torsional Restraint:", self.torsion_combo) + + self.warping_combo = QComboBox() + apply_field_style(self.warping_combo) + row = self._add_box_row(restraint_grid, row, "Warping Restraint:", self.warping_combo) + + self.web_type_combo = QComboBox() + apply_field_style(self.web_type_combo) + self._add_box_row(restraint_grid, row, "Web Type*:", self.web_type_combo, self.web_type_row) + + restraint_layout.addLayout(restraint_grid) + restraint_layout.addStretch(1) + left_column_layout.addWidget(restraint_box) + self._configure_restraint_fields() + + main_layout.addWidget(left_column) + + # Right side - image + section properties box + right_column = QWidget() + right_column.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + right_column_layout = QVBoxLayout(right_column) + right_column_layout.setContentsMargins(0, 0, 0, 0) + right_column_layout.setSpacing(12) + + # Dynamic image box + image_box = self._create_inner_box() + image_layout = QVBoxLayout(image_box) + image_layout.setContentsMargins(10, 10, 10, 10) + image_layout.setSpacing(5) + + self.section_preview = RolledSectionPreview() + image_layout.addWidget(self.section_preview, 1) + + self.preview_caption = QLabel("Provide girder inputs to preview") + self.preview_caption.setAlignment(Qt.AlignCenter) + self.preview_caption.setStyleSheet( + "QLabel { font-size: 13px; font-weight: 700; color: #1e1e1e; border: none; padding-top: 6px; font-family: 'Ubuntu Sans', 'Segoe UI', sans-serif; }" + ) + image_layout.addWidget(self.preview_caption) + + right_column_layout.addWidget(image_box) + + # Section Properties box + props_box = self._create_inner_box() + props_layout = QVBoxLayout(props_box) + props_layout.setContentsMargins(12, 10, 12, 10) + props_layout.setSpacing(10) + + props_title = self._create_label("Section Properties:") + props_layout.addWidget(props_title) + + properties_grid = QGridLayout() + properties_grid.setContentsMargins(0, 0, 0, 0) + properties_grid.setHorizontalSpacing(12) + properties_grid.setVerticalSpacing(10) + properties_grid.setColumnMinimumWidth(0, 140) + properties_grid.setColumnStretch(0, 0) + properties_grid.setColumnStretch(1, 1) + + property_fields = [ + "Mass, M (Kg/m)", + "Sectional Area, a (cm2)", + "2nd Moment of Area, Iz (cm4)", + "2nd Moment of Area, Iy (cm4)", + "Radius of Gyration, rz (cm)", + "Radius of Gyration, ry (cm)", + "Elastic Modulus, Zz (cm3)", + "Elastic Modulus, Zy (cm3)", + "Plastic Modulus, Zuz (cm3)", + "Plastic Modulus, Zuy (cm3)", + "Torsion Constant, It (cm4)", + "Warping Constant, Iw (cm6)" + ] + + for index, text in enumerate(property_fields): + label = self._create_small_label(text) + line_edit = self._create_line_edit() + line_edit.setPlaceholderText("") + properties_grid.addWidget(label, index, 0) + properties_grid.addWidget(line_edit, index, 1) + self.section_property_inputs[text] = line_edit + + props_layout.addLayout(properties_grid) + right_column_layout.addWidget(props_box) + + main_layout.addWidget(right_column) + + self.design_combo.currentTextChanged.connect(self._on_design_changed) + self.type_combo.currentTextChanged.connect(self._on_type_changed) + self.is_section_combo.currentTextChanged.connect(self._update_preview) + for watcher in (self.total_depth_input, self.top_width_input, self.bottom_width_input): + watcher.textChanged.connect(self._update_preview) + self._on_design_changed(self.design_combo.currentText()) + self._on_type_changed(self.type_combo.currentText()) + + return container + + def _create_card_frame(self): + frame = QFrame() + frame.setObjectName("girderCard") + frame.setStyleSheet("QFrame#girderCard { background-color: white; border: 1px solid #cfcfcf; border-radius: 10px; }") + return frame + + def _create_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 12px; color: #2f2f2f; font-weight: 600; background: transparent;") + label.setAutoFillBackground(False) + return label + + def _create_small_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 10px; color: #5a5a5a; background: transparent;") + label.setAutoFillBackground(False) + return label + + def _create_line_edit(self): + line_edit = QLineEdit() + apply_field_style(line_edit) + return line_edit + + def _add_section_row(self, layout, row, text, widget, tracker=None): + label = self._create_label(text) + widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self._set_field_width(widget) + layout.addWidget(label, row, 0) + layout.addWidget(widget, row, 1) + if tracker is not None: + tracker.append((label, widget)) + return row + 1 + + def _set_field_width(self, widget, width=230): + widget.setMaximumWidth(width) + widget.setMinimumWidth(min(width, 160)) + + def _setup_girder_selector(self): + if hasattr(self.select_girder_combo, "checkedItemsChanged"): + self.select_girder_combo.checkedItemsChanged.connect(self._on_girders_selection_changed) + self._on_girders_selection_changed() + + def _on_girders_selection_changed(self, *args): + if self.span_combo.currentText() == "Full Length": + self._update_member_id_edit_state() + return + current_text = self.member_id_input.text().strip() + if not self._is_valid_segment_id(current_text): + default_id = self._default_member_segment_id() + self._set_member_id_text(default_id) + self._update_member_id_edit_state() + + def _get_selected_girders(self): + selected = [] + if hasattr(self.select_girder_combo, "checked_items"): + selected = self.select_girder_combo.checked_items(include_all=True) + model = self.select_girder_combo.model() + if model is None: + return self.available_girders.copy() + all_checked = False + if selected: + all_checked = any(item.strip().lower() == "all" for item in selected) + else: + for row in range(model.rowCount()): + item = model.item(row) + if not item or item.checkState() != Qt.Checked: + continue + text = item.text() + if text.strip().lower() == "all": + all_checked = True + else: + selected.append(text) + if all_checked or not selected: + return self.available_girders.copy() + normalized = [text for text in selected if text in self.available_girders] + return normalized if normalized else self.available_girders.copy() + + def _default_member_segment_id(self, girders=None): + girders = girders or self._get_selected_girders() + base = girders[0] if girders else "G1" + return f"{base}-1" + + def _set_member_id_text(self, value, block_signals=False): + if block_signals: + previous = self.member_id_input.blockSignals(True) + self.member_id_input.setText(value) + self.member_id_input.blockSignals(previous) + else: + self.member_id_input.setText(value) + + def _is_valid_segment_id(self, member_id): + if not member_id or "-" not in member_id: + return False + base, index = self._split_member_id(member_id) + return bool(base and isinstance(index, int)) + + def _update_member_id_edit_state(self): + is_full_span = self.span_combo.currentText() == "Full Length" + self.member_id_input.setReadOnly(is_full_span) + if is_full_span: + girders = self._get_selected_girders() + display = ", ".join(girders) if girders else "G1" + self._set_member_id_text(display, block_signals=True) + else: + current_text = self.member_id_input.text().strip() + if not self._is_valid_segment_id(current_text): + default_id = self._default_member_segment_id() + self._set_member_id_text(default_id) + self._update_distance_field_states() + + def _on_design_changed(self, text): + is_custom = text.lower() == "customized" + toggle_targets = ( + self.type_combo, + self.symmetry_combo, + self.total_depth_input, + self.top_width_input, + self.bottom_width_input, + ) + for widget in toggle_targets: + widget.setEnabled(is_custom) + if not is_custom: + self._lock_type_to_welded() + self._reset_section_state() + self._apply_type_state() + + def _on_type_changed(self, text): + self._apply_type_state() + self._update_preview() + + def _apply_type_state(self): + is_welded = self.type_combo.currentText().lower() == "welded" + is_custom = self.design_combo.currentText().lower() == "customized" + + self._set_row_visibility(self.welded_rows, is_welded) + self._set_row_visibility(self.rolled_rows, not is_welded) + + for label, widget in self.symmetry_row: + label.setVisible(is_welded) + widget.setVisible(is_welded) + self.symmetry_combo.setEnabled(is_welded and is_custom) + + plate_widgets = ( + self.total_depth_input, + self.web_thickness_combo, + self.top_width_input, + self.top_thickness_combo, + self.bottom_width_input, + self.bottom_thickness_combo, + ) + for widget in plate_widgets: + widget.setEnabled(is_welded and is_custom) + widget.setVisible(is_welded) + + for label, widget in self.web_type_row: + label.setVisible(is_welded) + widget.setVisible(is_welded) + widget.setEnabled(is_welded and is_custom) + + self.is_section_combo.setVisible(not is_welded) + self.is_section_combo.setEnabled(not is_welded) + + def _lock_type_to_welded(self): + welded_index = self.type_combo.findText("Welded", Qt.MatchFixedString) + if welded_index != -1 and self.type_combo.currentIndex() != welded_index: + previous = self.type_combo.blockSignals(True) + self.type_combo.setCurrentIndex(welded_index) + self.type_combo.blockSignals(previous) + + def _reset_section_state(self): + for widget in (self.total_depth_input, self.top_width_input, self.bottom_width_input): + previous = widget.blockSignals(True) + widget.clear() + widget.blockSignals(previous) + self._update_preview() + + def _update_distance_field_states(self): + member_id = self.member_id_input.text().strip() + is_full_span = self.span_combo.currentText() == "Full Length" + if is_full_span: + self.distance_start_input.setReadOnly(True) + self.distance_end_input.setReadOnly(True) + return + if not self._is_valid_segment_id(member_id): + self.distance_start_input.setReadOnly(True) + self.distance_end_input.setReadOnly(True) + return + self.distance_start_input.setReadOnly(self._is_first_segment(member_id)) + self.distance_end_input.setReadOnly(False) + + def _on_span_changed(self, span_text): + is_full = span_text == "Full Length" + self.length_input.setReadOnly(not is_full) + if is_full: + self._apply_full_length_distances() + else: + member_id = self.member_id_input.text().strip() + if not self._is_valid_segment_id(member_id): + member_id = self._default_member_segment_id() + self._set_member_id_text(member_id) + self._load_segment_distances(member_id) + self._update_member_id_edit_state() + + def _on_length_changed(self, _): + if self.span_combo.currentText() == "Full Length": + self._apply_full_length_distances() + + def _apply_full_length_distances(self): + self._suppress_distance_updates = True + try: + total_span = self._get_total_span() + self._set_line_edit_value(self.distance_start_input, 0.0) + self._set_line_edit_value(self.distance_end_input, total_span) + finally: + self._suppress_distance_updates = False + + def _on_member_id_changed(self, member_id): + member_id = member_id.strip() + if not member_id or self.span_combo.currentText() == "Full Length": + return + if not self._is_valid_segment_id(member_id): + self._update_distance_field_states() + return + if self._is_first_segment(member_id): + self._update_segment_record(member_id, start=0.0) + else: + previous_id = self._get_previous_segment_id(member_id) + previous_end = self.segment_chain.get(previous_id, {}).get("end") if previous_id else None + if previous_end is not None: + self._update_segment_record(member_id, start=previous_end) + self._load_segment_distances(member_id) + self._update_distance_field_states() + + def _on_distance_start_changed(self): + if self._suppress_distance_updates: + return + current_id = self.member_id_input.text().strip() + if not current_id or not self._is_valid_segment_id(current_id): + return + if self._is_first_segment(current_id): + self._suppress_distance_updates = True + try: + self._set_line_edit_value(self.distance_start_input, 0.0) + finally: + self._suppress_distance_updates = False + self._update_segment_record(current_id, start=0.0) + return + value = self._parse_float(self.distance_start_input.text()) or 0.0 + self._update_segment_record(current_id, start=value) + + def _on_distance_end_changed(self): + if self._suppress_distance_updates: + return + current_id = self.member_id_input.text().strip() + if not current_id or self.span_combo.currentText() == "Full Length" or not self._is_valid_segment_id(current_id): + return + end_value = self._parse_float(self.distance_end_input.text()) + if end_value is None: + end_value = 0.0 + + start_value = self._parse_float(self.distance_start_input.text()) + if start_value is None: + start_value = self.segment_chain.get(current_id, {}).get("start") + if start_value is None and self._is_first_segment(current_id): + start_value = 0.0 + + if start_value is not None: + self._update_segment_record(current_id, start=start_value) + self._update_segment_record(current_id, end=end_value) + self._propagate_next_segment_start(current_id, end_value) + + def _propagate_next_segment_start(self, member_id, next_start_value): + next_id = self._get_next_segment_id(member_id) + if not next_id: + return + self._update_segment_record(next_id, start=next_start_value) + if next_id == self.member_id_input.text().strip() and self.span_combo.currentText() != "Full Length": + self._load_segment_distances(next_id) + + def _load_segment_distances(self, member_id): + if not member_id or not self._is_valid_segment_id(member_id): + return + record = self.segment_chain.setdefault(member_id, {}) + if self._is_first_segment(member_id): + record.setdefault("start", 0.0) + elif "start" not in record: + previous_id = self._get_previous_segment_id(member_id) + if previous_id: + previous = self.segment_chain.get(previous_id, {}) + if "end" in previous: + record["start"] = previous["end"] + + self._suppress_distance_updates = True + try: + if "start" in record: + self._set_line_edit_value(self.distance_start_input, record["start"]) + else: + self.distance_start_input.clear() + if "end" in record: + self._set_line_edit_value(self.distance_end_input, record["end"]) + else: + self.distance_end_input.clear() + finally: + self._suppress_distance_updates = False + + def _update_segment_record(self, member_id, start=None, end=None): + if not member_id or not self._is_valid_segment_id(member_id): + return + record = self.segment_chain.setdefault(member_id, {}) + if start is not None: + record["start"] = start + if end is not None: + record["end"] = end + + def _get_total_span(self): + return self._parse_float(self.length_input.text()) or 0.0 + + def _is_first_segment(self, member_id): + _, index = self._split_member_id(member_id) + return index == 1 + + def _get_next_segment_id(self, member_id): + base, index = self._split_member_id(member_id) + if base is None or index is None: + return None + return f"{base}-{index + 1}" + + def _get_previous_segment_id(self, member_id): + base, index = self._split_member_id(member_id) + if base is None or index is None or index <= 1: + return None + return f"{base}-{index - 1}" + + def _split_member_id(self, member_id): + if "-" not in member_id: + return member_id, None + base, index = member_id.rsplit("-", 1) + try: + return base, int(index) + except ValueError: + return base, None + + def _set_line_edit_value(self, line_edit, value): + if value is None: + return + text = f"{value:.3f}".rstrip("0").rstrip(".") + if not text: + text = "0" + previous_state = line_edit.blockSignals(True) + line_edit.setText(text) + line_edit.blockSignals(previous_state) + + def validate_member_properties(self) -> bool: + if self.design_combo.currentText() != "Customized": + return True + required_fields = [ + (self.total_depth_input, "Total Depth (d, mm)"), + (self.top_width_input, "Width of Top Flange (t_fw, mm)"), + (self.bottom_width_input, "Width of Bottom Flange (b_fw, mm)"), + ] + missing = [] + for field, label in required_fields: + value = self._parse_float(field.text()) + if value is None or value <= 0: + missing.append(label) + if missing: + QMessageBox.critical( + self, + "Incomplete Girder Inputs", + f"Please provide valid values for: {', '.join(missing)}.", + ) + return False + return True + + def _create_inner_box(self): + """Create a bordered box for grouped controls""" + box = QFrame() + box.setStyleSheet(""" + QFrame { + border: 1px solid #b0b0b0; + border-radius: 6px; + background-color: #ffffff; + } + QFrame QComboBox, QFrame QLineEdit { + border: none; + border-bottom: 1px solid #d0d0d0; + border-radius: 0px; + min-height: 28px; + padding: 4px 8px; + background-color: #ffffff; + } + QFrame QComboBox:hover, QFrame QLineEdit:hover { + border-bottom: 1px solid #5d5d5d; + } + QFrame QComboBox:focus, QFrame QLineEdit:focus { + border-bottom: 1px solid #90AF13; + } + QFrame QLabel { + border: none; + padding: 0px; + margin: 0px; + } + """) + return box + + def _create_small_label(self, text): + """Create a smaller label for compact layouts""" + label = QLabel(text) + label.setStyleSheet(""" + QLabel { + color: #2b2b2b; + font-size: 11px; + font-weight: 500; + background: transparent; + border: none; + padding: 0px; + margin: 0px; + } + """) + label.setAutoFillBackground(False) + return label + + def _add_box_row(self, layout, row, label_text, widget, visibility_list=None): + """Add a row to a box grid layout""" + label = self._create_small_label(label_text) + layout.addWidget(label, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + layout.addWidget(widget, row, 1) + if visibility_list is not None: + visibility_list.append((label, widget)) + return row + 1 + + def _set_row_visibility(self, rows, visible): + for label, widget in rows: + label.setVisible(visible) + widget.setVisible(visible) + + def _populate_rolled_section_combo(self): + designations = sorted(girder_properties.list_available_sections().keys()) + if not designations: + designations = [ + "ISMB 500", "ISMB 550", "ISMB 600", + "ISWB 500", "ISWB 550", "ISWB 600", + ] + self.is_section_combo.clear() + self.is_section_combo.addItems(designations) + + def _configure_restraint_fields(self): + torsion_items = self._constant_items("VALUES_TORSIONAL_RESTRAINT") + warping_items = self._constant_items("VALUES_WARPING_RESTRAINT") + web_type_items = self._constant_items("VALUES_WEB_TYPE") + + self._reload_combo_items(self.torsion_combo, torsion_items) + self._reload_combo_items(self.warping_combo, warping_items) + self._reload_combo_items(self.web_type_combo, web_type_items) + + @staticmethod + def _reload_combo_items(combo, items): + block = combo.blockSignals(True) + combo.clear() + combo.addItems(items) + combo.setCurrentIndex(0 if items else -1) + combo.blockSignals(block) + + @staticmethod + def _constant_items(constant_name): + return list(globals().get(constant_name, [])) + + def _update_preview(self): + if not hasattr(self, "section_preview"): + return + + is_welded = self.type_combo.currentText().lower() == "welded" + if is_welded: + dims = self._gather_welded_dimensions() + caption = "Welded girder preview" if dims else "Enter depth and flange widths" + if dims: + self.section_preview.set_dimensions( + depth_mm=dims["depth_mm"], + flange_width_mm=dims["top_flange_width_mm"], + bottom_flange_width_mm=dims["bottom_flange_width_mm"], + web_thickness_mm=dims["web_thickness_mm"], + flange_thickness_mm=dims["top_flange_thickness_mm"], + bottom_flange_thickness_mm=dims["bottom_flange_thickness_mm"], + show_welds=True, + ) + else: + self.section_preview.clear() + else: + designation = self.is_section_combo.currentText() + beam = girder_properties.get_beam_profile(designation) + outline = girder_properties.get_rolled_section(designation) if beam is None else None + has_data = bool(beam or outline) + caption = f"Rolled section • {designation}" if has_data else "Rolled section unavailable" + if beam: + self.section_preview.set_section(beam) + elif outline: + self.section_preview.set_dimensions( + depth_mm=outline["depth_mm"], + flange_width_mm=outline["top_flange_width_mm"], + bottom_flange_width_mm=outline["bottom_flange_width_mm"], + web_thickness_mm=outline["web_thickness_mm"], + flange_thickness_mm=outline["top_flange_thickness_mm"], + bottom_flange_thickness_mm=outline["bottom_flange_thickness_mm"], + ) + else: + self.section_preview.clear() + + if hasattr(self, "preview_caption"): + self.preview_caption.setText(caption) + self._update_section_properties() + + def _gather_welded_dimensions(self): + depth = self._parse_float(self.total_depth_input.text()) + top_width = self._parse_float(self.top_width_input.text()) + bottom_width = self._parse_float(self.bottom_width_input.text()) or top_width + + if not depth or not top_width or not bottom_width: + return None + + web_thickness = max(8.0, depth * 0.02) + flange_thickness = max(10.0, depth * 0.03) + + return { + "designation": "Custom Welded Girder", + "section_type": "welded", + "depth_mm": depth, + "top_flange_width_mm": top_width, + "bottom_flange_width_mm": bottom_width, + "web_thickness_mm": web_thickness, + "top_flange_thickness_mm": flange_thickness, + "bottom_flange_thickness_mm": flange_thickness, + } + + def _update_section_properties(self): + if not self.section_property_inputs: + return + values = None + if self.type_combo.currentText().lower() == "welded": + dims = self._gather_welded_dimensions() + if dims: + values = self._compute_welded_properties(dims) + else: + designation = self.is_section_combo.currentText() + values = self._fetch_rolled_properties(designation) + if values: + self._apply_section_properties(values) + else: + self._clear_section_properties() + + def _fetch_rolled_properties(self, designation): + if not designation: + return None + beam = girder_properties.get_beam_profile(designation) + if not beam: + return None + values = { + "Mass, M (Kg/m)": beam.mass_per_meter_kg, + "Sectional Area, a (cm2)": beam.area_cm2, + "2nd Moment of Area, Iz (cm4)": beam.moment_of_inertia_zz_cm4, + "2nd Moment of Area, Iy (cm4)": beam.moment_of_inertia_yy_cm4, + "Radius of Gyration, rz (cm)": beam.radius_of_gyration_z_cm, + "Radius of Gyration, ry (cm)": beam.radius_of_gyration_y_cm, + "Elastic Modulus, Zz (cm3)": beam.elastic_section_modulus_z_cm3, + "Elastic Modulus, Zy (cm3)": beam.elastic_section_modulus_y_cm3, + "Plastic Modulus, Zuz (cm3)": beam.plastic_section_modulus_z_cm3, + "Plastic Modulus, Zuy (cm3)": beam.plastic_section_modulus_y_cm3, + "Torsion Constant, It (cm4)": beam.torsion_constant_cm4, + "Warping Constant, Iw (cm6)": beam.warping_constant_cm6, + } + area = values.get("Sectional Area, a (cm2)") + iz = values.get("2nd Moment of Area, Iz (cm4)") + iy = values.get("2nd Moment of Area, Iy (cm4)") + if values.get("Radius of Gyration, rz (cm)") is None and area and iz: + values["Radius of Gyration, rz (cm)"] = math.sqrt(iz / area) + if values.get("Radius of Gyration, ry (cm)") is None and area and iy: + values["Radius of Gyration, ry (cm)"] = math.sqrt(iy / area) + return values + + def _compute_welded_properties(self, dims): + depth = dims["depth_mm"] + top_width = dims["top_flange_width_mm"] + bottom_width = dims["bottom_flange_width_mm"] + web_thickness = dims["web_thickness_mm"] + top_thickness = dims["top_flange_thickness_mm"] + bottom_thickness = dims["bottom_flange_thickness_mm"] + + h_web = max(depth - top_thickness - bottom_thickness, 1.0) + area_top = top_width * top_thickness + area_bottom = bottom_width * bottom_thickness + area_web = web_thickness * h_web + area_total_mm2 = area_top + area_bottom + area_web + area_cm2 = area_total_mm2 / 100.0 + mass_kg_per_m = (area_total_mm2 / 1_000_000.0) * 7850.0 + + iz_web = (web_thickness * h_web ** 3) / 12.0 + iz_top = (top_width * top_thickness ** 3) / 12.0 + iz_bottom = (bottom_width * bottom_thickness ** 3) / 12.0 + distance_top = h_web / 2.0 + top_thickness / 2.0 + distance_bottom = h_web / 2.0 + bottom_thickness / 2.0 + iz_top += area_top * distance_top ** 2 + iz_bottom += area_bottom * distance_bottom ** 2 + iz_cm4 = (iz_web + iz_top + iz_bottom) / 10000.0 + + iy_web = (h_web * web_thickness ** 3) / 12.0 + iy_top = (top_thickness * top_width ** 3) / 12.0 + iy_bottom = (bottom_thickness * bottom_width ** 3) / 12.0 + iy_cm4 = (iy_web + iy_top + iy_bottom) / 10000.0 + + rz_cm = math.sqrt(iz_cm4 / area_cm2) if area_cm2 > 0 else None + ry_cm = math.sqrt(iy_cm4 / area_cm2) if area_cm2 > 0 else None + + depth_cm = depth / 10.0 + width_cm = max(top_width, bottom_width) / 10.0 + zz_cm3 = iz_cm4 / (depth_cm / 2.0) if depth_cm > 0 else None + zy_cm3 = iy_cm4 / (width_cm / 2.0) if width_cm > 0 else None + + zpl_major = ( + area_top * distance_top + + area_bottom * distance_bottom + + (web_thickness * h_web ** 2) / 4.0 + ) / 1000.0 + zpl_minor = ( + (top_thickness * top_width ** 2) / 4.0 + + (bottom_thickness * bottom_width ** 2) / 4.0 + + (h_web * web_thickness ** 2) / 4.0 + ) / 1000.0 + + torsion_constant_cm4 = ( + (top_width * top_thickness ** 3) / 3.0 + + (bottom_width * bottom_thickness ** 3) / 3.0 + + (h_web * web_thickness ** 3) / 3.0 + ) / 10000.0 + + warping_constant_cm6 = ( + ((top_width * top_thickness ** 3) + (bottom_width * bottom_thickness ** 3)) * h_web ** 2 / 24.0 + ) / 1_000_000.0 + + return { + "Mass, M (Kg/m)": mass_kg_per_m, + "Sectional Area, a (cm2)": area_cm2, + "2nd Moment of Area, Iz (cm4)": iz_cm4, + "2nd Moment of Area, Iy (cm4)": iy_cm4, + "Radius of Gyration, rz (cm)": rz_cm, + "Radius of Gyration, ry (cm)": ry_cm, + "Elastic Modulus, Zz (cm3)": zz_cm3, + "Elastic Modulus, Zy (cm3)": zy_cm3, + "Plastic Modulus, Zuz (cm3)": zpl_major, + "Plastic Modulus, Zuy (cm3)": zpl_minor, + "Torsion Constant, It (cm4)": torsion_constant_cm4, + "Warping Constant, Iw (cm6)": warping_constant_cm6, + } + + def _apply_section_properties(self, values): + for label, widget in self.section_property_inputs.items(): + display = self._format_property_value(values.get(label)) + previous = widget.blockSignals(True) + widget.setText(display) + widget.blockSignals(previous) + + def _clear_section_properties(self): + for widget in self.section_property_inputs.values(): + previous = widget.blockSignals(True) + widget.clear() + widget.blockSignals(previous) + + @staticmethod + def _format_property_value(value): + if value is None: + return "" + if isinstance(value, (int, float)): + return f"{value:.2f}" + return str(value) + + @staticmethod + def _parse_float(text): + try: + return float(text) + except (TypeError, ValueError): + return None + +class StiffenerDetailsTab(QWidget): + """Tab for Stiffener Details with compact layout""" + + def __init__(self, parent=None): + super().__init__(parent) + self.init_ui() + + def init_ui(self): + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setStyleSheet( + "QScrollArea { border: none; background: transparent; }" + "QScrollArea > QWidget > QWidget { background: transparent; }" + ) + main_layout.addWidget(scroll) + + container = QWidget() + scroll.setWidget(container) + container.setStyleSheet("background-color: #f4f4f4;") + + container_layout = QVBoxLayout(container) + container_layout.setContentsMargins(0, 0, 0, 0) + container_layout.setSpacing(4) + + # Combined card for inputs and description + card_frame = self._create_card_frame() + card_layout = QHBoxLayout(card_frame) + card_layout.setContentsMargins(18, 16, 18, 16) + card_layout.setSpacing(18) + + # Left column - inputs + left_column = QWidget() + left_layout = QVBoxLayout(left_column) + left_layout.setContentsMargins(0, 0, 0, 0) + left_layout.setSpacing(12) + + girder_row = QHBoxLayout() + girder_row.setContentsMargins(0, 0, 0, 0) + girder_row.setSpacing(10) + + girder_label = QLabel("Select Girder Member:") + girder_label.setStyleSheet("font-size: 11px; font-weight: 600; color: #3a3a3a; border: none;") + girder_row.addWidget(girder_label) + + self.girder_member_combo = QComboBox() + self.girder_member_combo.addItems(["G1-1", "G1-2", "G1-3", "All"]) + apply_field_style(self.girder_member_combo) + self.girder_member_combo.setFixedWidth(190) + self.girder_member_combo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + girder_row.addWidget(self.girder_member_combo, 1) + + left_layout.addLayout(girder_row) + + stiffener_heading = QLabel("Stiffener Inputs") + stiffener_heading.setStyleSheet("font-size: 11px; font-weight: 700; color: #000000; border: none; margin-top: 4px;") + left_layout.addWidget(stiffener_heading) + + inputs_grid = QGridLayout() + inputs_grid.setContentsMargins(0, 0, 0, 0) + inputs_grid.setHorizontalSpacing(12) + inputs_grid.setVerticalSpacing(10) + inputs_grid.setColumnMinimumWidth(0, 180) + inputs_grid.setColumnStretch(0, 0) + inputs_grid.setColumnStretch(1, 1) + + self.intermediate_combo = QComboBox() + self.intermediate_combo.addItems(["No", "Yes - At Supports", "Yes - Spaced"]) + apply_field_style(self.intermediate_combo) + row = self._add_form_row(inputs_grid, 0, "Intermediate Stiffener:", self.intermediate_combo) + + self.spacing_field = OptimizableField("Intermediate Stiffener Spacing") + self.spacing_field.mode_combo.clear() + self.spacing_field.mode_combo.addItems(["NA", "Optimized", "Customized"]) + self.spacing_field.on_mode_changed(self.spacing_field.mode_combo.currentText()) + self._prepare_optimizable_field(self.spacing_field) + row = self._add_form_row(inputs_grid, row, "Intermediate Stiffener Spacing:", self.spacing_field) + + self.longitudinal_combo = QComboBox() + self.longitudinal_combo.addItems(["None", "Yes and 1 stiffener", "Yes and 2 stiffeners"]) + apply_field_style(self.longitudinal_combo) + row = self._add_form_row(inputs_grid, row, "Longitudinal Stiffener:", self.longitudinal_combo) + + self.intermediate_thick_combo = QComboBox() + self.intermediate_thick_combo.addItems(["All", "Custom"]) + apply_field_style(self.intermediate_thick_combo) + row = self._add_form_row(inputs_grid, row, "Intermediate Stiffener Thickness:", self.intermediate_thick_combo) + + self.long_thick_combo = QComboBox() + self.long_thick_combo.addItems(["All", "Custom"]) + self.long_thick_combo.setEnabled(False) + apply_field_style(self.long_thick_combo) + row = self._add_form_row(inputs_grid, row, "Longitudinal Stiffener Thickness:", self.long_thick_combo) + + left_layout.addLayout(inputs_grid) + + buckling_heading = QLabel("Web Buckling Details") + buckling_heading.setStyleSheet("font-size: 11px; font-weight: 700; color: #000000; border: none; margin-top: 4px;") + left_layout.addWidget(buckling_heading) + + buckling_grid = QGridLayout() + buckling_grid.setContentsMargins(0, 0, 0, 0) + buckling_grid.setHorizontalSpacing(12) + buckling_grid.setVerticalSpacing(10) + buckling_grid.setColumnMinimumWidth(0, 180) + + self.method_combo = QComboBox() + self.method_combo.addItems(VALUES_STIFFENER_DESIGN) + apply_field_style(self.method_combo) + self._add_form_row(buckling_grid, 0, "Shear Buckling Design Method:", self.method_combo) + + left_layout.addLayout(buckling_grid) + + card_layout.addWidget(left_column, 2) + + # Right column - description + right_column = QWidget() + right_layout = QVBoxLayout(right_column) + right_layout.setContentsMargins(0, 0, 0, 0) + right_layout.setSpacing(8) + + desc_heading = QLabel("Description") + desc_heading.setStyleSheet("font-size: 11px; font-weight: 700; color: #000000; border: none;") + right_layout.addWidget(desc_heading) + + self.description_text = QTextEdit() + self.description_text.setReadOnly(True) + self.description_text.setPlaceholderText("Describe stiffener assumptions or notes here.") + self.description_text.setMinimumHeight(210) + self.description_text.setStyleSheet( + "QTextEdit { border: 1px solid #d0d0d0; border-radius: 6px; background: #ffffff; color: #3a3a3a; font-size: 11px; }" + ) + right_layout.addWidget(self.description_text, 1) + + card_layout.addWidget(right_column, 3) + + container_layout.addWidget(card_frame) + + # Dynamic image box + image_box = self._create_card_frame() + image_layout = QVBoxLayout(image_box) + image_layout.setContentsMargins(16, 16, 16, 16) + image_layout.setSpacing(8) + + self.dynamic_image_label = QLabel("Dynamic Image") + self.dynamic_image_label.setAlignment(Qt.AlignCenter) + self.dynamic_image_label.setMinimumHeight(140) + self.dynamic_image_label.setStyleSheet( + "QLabel { border: 1px solid #d8d8d8; border-radius: 8px; background-color: #f8f8f8; " + "font-weight: 600; color: #5b5b5b; font-size: 11px; }" + ) + image_layout.addWidget(self.dynamic_image_label) + container_layout.addWidget(image_box) + + + # Signals + self.longitudinal_combo.currentTextChanged.connect(self.on_longitudinal_changed) + + def _create_card_frame(self): + card = QFrame() + card.setStyleSheet( + "QFrame { border: 1px solid #d6d6d6; border-radius: 8px; background-color: #f7f7f7; }" + ) + return card + + def _create_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 11px; color: #3a3a3a; border: none;") + return label + + def _add_form_row(self, layout, row, text, widget): + label = self._create_label(text) + layout.addWidget(label, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + layout.addWidget(widget, row, 1) + return row + 1 + + def _prepare_optimizable_field(self, field): + field.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + apply_field_style(field.mode_combo) + apply_field_style(field.input_field) + + def on_longitudinal_changed(self, text): + has_longitudinal = text.lower().startswith("yes") + self.long_thick_combo.setEnabled(has_longitudinal) + +class CrossBracingDetailsTab(QWidget): + """Tab for Cross-Bracing Details with visual previews""" + + def __init__(self, parent=None): + super().__init__(parent) + self.init_ui() + + def init_ui(self): + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setStyleSheet( + "QScrollArea { border: none; background: transparent; }" + "QScrollArea > QWidget > QWidget { background: transparent; }" + ) + main_layout.addWidget(scroll) + + container = QWidget() + scroll.setWidget(container) + + container_layout = QVBoxLayout(container) + container_layout.setContentsMargins(0, 0, 0, 0) + container_layout.setSpacing(16) + + primary_card = self._create_card_frame() + card_layout = QHBoxLayout(primary_card) + card_layout.setContentsMargins(12, 10, 12, 10) + card_layout.setSpacing(10) + + # Left column (inputs) + left_column = QWidget() + left_column.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + left_layout = QVBoxLayout(left_column) + left_layout.setContentsMargins(0, 0, 0, 0) + left_layout.setSpacing(4) + + selection_box = self._create_inner_box() + selection_layout = QGridLayout(selection_box) + selection_layout.setContentsMargins(8, 4, 8, 4) + selection_layout.setHorizontalSpacing(8) + selection_layout.setVerticalSpacing(4) + selection_layout.setColumnMinimumWidth(0, 130) + selection_layout.setColumnStretch(1, 1) + + self.select_girders_combo = QComboBox() + self.select_girders_combo.addItems(["G1 to G2", "G3 to G4", "All"]) + apply_field_style(self.select_girders_combo) + selection_layout.addWidget(self._create_label("Select Girders:"), 0, 0) + selection_layout.addWidget(self.select_girders_combo, 0, 1) + + self.member_id_combo = QComboBox() + self.member_id_combo.addItems(["B1-1 to B1-15", "B2-1 to B2-10", "Custom"]) + apply_field_style(self.member_id_combo) + selection_layout.addWidget(self._create_label("Member ID:"), 1, 0) + selection_layout.addWidget(self.member_id_combo, 1, 1) + + left_layout.addWidget(selection_box) + + inputs_box = self._create_inner_box() + inputs_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + inputs_layout = QVBoxLayout(inputs_box) + inputs_layout.setContentsMargins(12, 8, 12, 8) + inputs_layout.setSpacing(6) + inputs_layout.addWidget(self._create_heading_label("Section Inputs:")) + + inputs_grid = QGridLayout() + inputs_grid.setContentsMargins(0, 0, 0, 0) + inputs_grid.setHorizontalSpacing(16) + inputs_grid.setVerticalSpacing(12) + inputs_grid.setColumnMinimumWidth(0, 130) + inputs_grid.setColumnStretch(0, 0) + inputs_grid.setColumnStretch(1, 1) + + self.design_combo = QComboBox() + self.design_combo.addItems(["Customized", "Optimized"]) + apply_field_style(self.design_combo) + row = self._add_grid_row(inputs_grid, 0, "Design:", self.design_combo) + + self.bracing_type_combo = QComboBox() + self.bracing_type_combo.addItems(["K-Bracing", "X-Bracing", "Diagonal", "Horizontal"]) + apply_field_style(self.bracing_type_combo) + row = self._add_grid_row(inputs_grid, row, "Type of Bracing:", self.bracing_type_combo) + + section_options = [ + "ISA 50 x 50 x 6", "ISA 65 x 65 x 6", "ISA 75 x 75 x 6", + "ISA 90 x 90 x 8", "ISA 100 x 100 x 8", "ISA 110 x 110 x 10", + "ISA 130 x 130 x 10", "ISMC 75", "ISMC 100", "ISMC 125", + "ISMC 150", "2-ISA 65 x 65 x 6", "2-ISA 75 x 75 x 6" + ] + + self.bracing_section_combo = QComboBox() + self.bracing_section_combo.addItems(section_options) + apply_field_style(self.bracing_section_combo) + row = self._add_grid_row(inputs_grid, row, "Bracing Section:", self.bracing_section_combo) + + self.top_bracket_type_combo = QComboBox() + self.top_bracket_type_combo.addItems(["Double Angles", "Single Angle", "Channel"]) + apply_field_style(self.top_bracket_type_combo) + row = self._add_grid_row(inputs_grid, row, "Top Bracket Section:", self.top_bracket_type_combo) + + self.top_bracket_size_combo = QComboBox() + self.top_bracket_size_combo.addItems(section_options) + apply_field_style(self.top_bracket_size_combo) + row = self._add_grid_row(inputs_grid, row, "Top Bracket Size:", self.top_bracket_size_combo) + + self.bottom_bracket_type_combo = QComboBox() + self.bottom_bracket_type_combo.addItems(["Double Angles", "Single Angle", "Channel"]) + apply_field_style(self.bottom_bracket_type_combo) + row = self._add_grid_row(inputs_grid, row, "Bottom Bracket Section:", self.bottom_bracket_type_combo) + + self.bottom_bracket_size_combo = QComboBox() + self.bottom_bracket_size_combo.addItems(section_options) + apply_field_style(self.bottom_bracket_size_combo) + row = self._add_grid_row(inputs_grid, row, "Bottom Bracket Size:", self.bottom_bracket_size_combo) + + self.spacing_input = QLineEdit() + self.spacing_input.setPlaceholderText("Spacing (mm)") + self.spacing_input.setValidator(QDoubleValidator(0, 100000, 2)) + apply_field_style(self.spacing_input) + self._add_grid_row(inputs_grid, row, "Spacing:", self.spacing_input) + + inputs_layout.addLayout(inputs_grid) + left_layout.addWidget(inputs_box) + + card_layout.addWidget(left_column) + + # Right column (previews) + right_column = QWidget() + right_column.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + right_layout = QVBoxLayout(right_column) + right_layout.setContentsMargins(0, 0, 0, 0) + right_layout.setSpacing(14) + + type_box = self._create_inner_box() + type_layout = QVBoxLayout(type_box) + type_layout.setContentsMargins(12, 10, 12, 10) + type_layout.setSpacing(10) + type_layout.addWidget(self._create_heading_label("Type of Bracing")) + self.bracing_image_label = self._create_image_placeholder(210) + type_layout.addWidget(self.bracing_image_label) + right_layout.addWidget(type_box) + + self.bracing_preview_box, self.bracing_preview_label = self._create_preview_box("Bracing") + right_layout.addWidget(self.bracing_preview_box) + + self.top_bracket_preview_box, self.top_bracket_preview_label = self._create_preview_box("Top Bracket") + right_layout.addWidget(self.top_bracket_preview_box) + + self.bottom_bracket_preview_box, self.bottom_bracket_preview_label = self._create_preview_box("Bottom Bracket") + right_layout.addWidget(self.bottom_bracket_preview_box) + + card_layout.addWidget(right_column) + card_layout.setStretch(0, 3) + card_layout.setStretch(1, 2) + container_layout.addWidget(primary_card) + container_layout.addStretch() + + self.bracing_type_combo.currentTextChanged.connect(self._update_previews) + self.bracing_section_combo.currentTextChanged.connect(self._update_previews) + self.top_bracket_size_combo.currentTextChanged.connect(self._update_previews) + self.bottom_bracket_size_combo.currentTextChanged.connect(self._update_previews) + self._update_previews() + + def _create_card_frame(self): + card = QFrame() + card.setStyleSheet("QFrame { border: 1px solid #d0d0d0; border-radius: 12px; background-color: #ffffff; }") + return card + + def _create_inner_box(self): + box = QFrame() + box.setStyleSheet( + "QFrame { border: 1px solid #cfcfcf; border-radius: 8px; background-color: #ffffff; }" + "QFrame QComboBox, QFrame QLineEdit { border: none; border-bottom: 1px solid #d0d0d0; border-radius: 0px; min-height: 28px; padding: 4px 8px; background-color: #ffffff; }" + "QFrame QComboBox:hover, QFrame QLineEdit:hover { border-bottom: 1px solid #5d5d5d; }" + "QFrame QComboBox:focus, QFrame QLineEdit:focus { border-bottom: 1px solid #90AF13; }" + "QFrame QLabel { border: none; }" + ) + return box + + def _create_heading_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 12px; font-weight: 600; color: #4b4b4b; border: none;") + return label + + def _create_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 11px; color: #4b4b4b; border: none;") + return label + + def _add_grid_row(self, layout, row, text, widget): + label = self._create_label(text) + layout.addWidget(label, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + layout.addWidget(widget, row, 1) + return row + 1 + + def _create_image_placeholder(self, height): + label = QLabel("Bracing Preview") + label.setAlignment(Qt.AlignCenter) + label.setMinimumHeight(height) + label.setStyleSheet("QLabel { border: 1px solid #d0d0d0; border-radius: 10px; background-color: #f7f7f7; font-weight: bold; color: #5b5b5b; }") + return label + + def _create_preview_box(self, title): + box = self._create_inner_box() + layout = QVBoxLayout(box) + layout.setContentsMargins(12, 10, 12, 10) + layout.setSpacing(8) + layout.addWidget(self._create_heading_label(title)) + image = self._create_image_placeholder(120) + layout.addWidget(image) + return box, image + + def _update_previews(self): + self.bracing_image_label.setText(self.bracing_type_combo.currentText()) + self.bracing_preview_label.setText(self.bracing_section_combo.currentText()) + self.top_bracket_preview_label.setText(self.top_bracket_size_combo.currentText()) + self.bottom_bracket_preview_label.setText(self.bottom_bracket_size_combo.currentText()) + +class EndDiaphragmDetailsTab(QWidget): + """Tab for End Diaphragm Details with type-specific layouts""" + + def __init__(self, parent=None): + super().__init__(parent) + self.init_ui() + + def init_ui(self): + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setStyleSheet( + "QScrollArea { border: none; background: transparent; }" + "QScrollArea > QWidget > QWidget { background: transparent; }" + ) + main_layout.addWidget(scroll) + + container = QWidget() + scroll.setWidget(container) + + container_layout = QVBoxLayout(container) + container_layout.setContentsMargins(0, 0, 0, 0) + container_layout.setSpacing(8) + + self.type_stack = QStackedWidget() + container_layout.addWidget(self.type_stack) + + self.views = {} + self.view_order = [] + self.type_selector_map = {} + self.type_selectors = [] + self.current_type = None + self.block_type_sync = False + + cross_view, cross_selector = self._build_cross_bracing_view() + self._add_type_view("Cross Bracing", cross_view, cross_selector) + rolled_view, rolled_selector = self._build_rolled_view() + self._add_type_view("Rolled Beam", rolled_view, rolled_selector) + welded_view, welded_selector = self._build_welded_view() + self._add_type_view("Welded Beam", welded_view, welded_selector) + + self._set_current_type("Cross Bracing") + + def _add_type_view(self, key, widget, type_selector): + self.views[key] = widget + self.view_order.append(key) + self.type_stack.addWidget(widget) + self.type_selector_map[key] = type_selector + self.type_selectors.append(type_selector) + type_selector.currentTextChanged.connect(self._handle_type_selection) + + # ---- Shared helpers ---- + def _create_card_frame(self): + card = QFrame() + card.setStyleSheet("QFrame { border: 1px solid #d0d0d0; border-radius: 12px; background-color: #ffffff; }") + return card + + def _create_inner_box(self): + box = QFrame() + box.setStyleSheet( + "QFrame { border: 1px solid #cfcfcf; border-radius: 8px; background-color: #ffffff; padding: 0px; margin: 0px; }" + "QFrame QComboBox, QFrame QLineEdit { border: none; border-bottom: 1px solid #d0d0d0; border-radius: 0px; min-height: 28px; padding: 4px 8px; background-color: #ffffff; }" + "QFrame QComboBox:hover, QFrame QLineEdit:hover { border-bottom: 1px solid #5d5d5d; }" + "QFrame QComboBox:focus, QFrame QLineEdit:focus { border-bottom: 1px solid #90AF13; }" + "QFrame QLabel { border: none; padding: 0px; margin: 0px; }" + ) + return box + + def _create_heading_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 12px; font-weight: 600; color: #4b4b4b; border: none; padding: 0px; margin: 0px;") + return label + + def _create_label(self, text): + label = QLabel(text) + label.setStyleSheet("font-size: 11px; color: #4b4b4b; border: none;") + return label + + def _add_grid_row(self, layout, row, text, widget): + label = self._create_label(text) + layout.addWidget(label, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + layout.addWidget(widget, row, 1) + return row + 1 + + def _create_image_placeholder(self, text, min_height=140): + label = QLabel(text) + label.setAlignment(Qt.AlignCenter) + label.setMinimumHeight(min_height) + label.setStyleSheet("QLabel { border: 1px solid #d0d0d0; border-radius: 10px; background-color: #f7f7f7; font-weight: bold; color: #5b5b5b; }") + return label + + def _create_line_edit(self, placeholder=""): + line_edit = QLineEdit() + if placeholder: + line_edit.setPlaceholderText(placeholder) + apply_field_style(line_edit) + return line_edit + + def _create_selection_box(self): + box = self._create_inner_box() + box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + layout = QGridLayout(box) + layout.setContentsMargins(10, 8, 10, 8) + layout.setHorizontalSpacing(12) + layout.setVerticalSpacing(8) + layout.setColumnMinimumWidth(0, 120) + layout.setColumnStretch(1, 1) + + girders_combo = QComboBox() + girders_combo.addItems(["G1 to G2", "G3 to G4", "All"]) + apply_field_style(girders_combo) + layout.addWidget(self._create_label("Select Girders:"), 0, 0) + layout.addWidget(girders_combo, 0, 1) + + member_combo = QComboBox() + member_combo.addItems(["E1-1, E1-2", "E2-1, E2-2", "Custom"]) + apply_field_style(member_combo) + layout.addWidget(self._create_label("Member ID:"), 1, 0) + layout.addWidget(member_combo, 1, 1) + + return box + + def _create_section_properties_box(self, title): + box = self._create_inner_box() + layout = QVBoxLayout(box) + layout.setContentsMargins(12, 10, 12, 10) + layout.setSpacing(10) + layout.addWidget(self._create_heading_label(title)) + + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(12) + grid.setVerticalSpacing(10) + grid.setColumnMinimumWidth(0, 150) + grid.setColumnStretch(0, 0) + grid.setColumnStretch(1, 1) + + properties = [ + "Mass, M (Kg/m)", + "Sectional Area, a (cm2)", + "2nd Moment of Area, Iz (cm4)", + "2nd Moment of Area, Iy (cm4)", + "Radius of Gyration, rz (cm)", + "Radius of Gyration, ry (cm)", + "Elastic Modulus, Zz (cm3)", + "Elastic Modulus, Zy (cm3)", + "Plastic Modulus, Zuz (cm3)", + "Plastic Modulus, Zuy (cm3)" + ] + + inputs = {} + for row, name in enumerate(properties): + label = self._create_label(name) + field = self._create_line_edit() + grid.addWidget(label, row, 0) + grid.addWidget(field, row, 1) + inputs[name] = field + + layout.addLayout(grid) + return box, inputs + + # ---- View builders ---- + def _build_cross_bracing_view(self): + view = self._create_card_frame() + layout = QHBoxLayout(view) + layout.setContentsMargins(12, 12, 12, 12) + layout.setSpacing(12) + + left_column = QWidget() + left_layout = QVBoxLayout(left_column) + left_layout.setContentsMargins(0, 0, 0, 0) + left_layout.setSpacing(6) + left_layout.addWidget(self._create_selection_box()) + + inputs_box = self._create_inner_box() + inputs_layout = QVBoxLayout(inputs_box) + inputs_layout.setContentsMargins(12, 4, 12, 8) + inputs_layout.setSpacing(6) + title = self._create_heading_label("Section Inputs:") + title.setStyleSheet("font-size: 12px; font-weight: 600; color: #4b4b4b; border: none; margin-top: 0px; margin-bottom: 2px;") + inputs_layout.addWidget(title) + + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(12) + grid.setVerticalSpacing(10) + grid.setColumnMinimumWidth(0, 130) + grid.setColumnStretch(0, 0) + grid.setColumnStretch(1, 1) + + design_combo = QComboBox() + design_combo.addItems(["Customized", "Optimized"]) + apply_field_style(design_combo) + row = self._add_grid_row(grid, 0, "Design:", design_combo) + + type_selector = QComboBox() + type_selector.addItems(VALUES_END_DIAPHRAGM_TYPE) + type_selector.setCurrentText("Cross Bracing") + apply_field_style(type_selector) + row = self._add_grid_row(grid, row, "Type:", type_selector) + + bracing_combo = QComboBox() + bracing_combo.addItems(["K-Bracing", "X-Bracing", "Diagonal", "Horizontal"]) + apply_field_style(bracing_combo) + row = self._add_grid_row(grid, row, "Type of Bracing:", bracing_combo) + + section_options = [ + "Double Angles", "Single Angle", "Channel", + "ISA 100 x 100 x 8", "ISA 110 x 110 x 10" + ] + + bracing_section = QComboBox() + bracing_section.addItems(section_options) + apply_field_style(bracing_section) + row = self._add_grid_row(grid, row, "Bracing Section:", bracing_section) + + top_bracket = QComboBox() + top_bracket.addItems(section_options) + apply_field_style(top_bracket) + row = self._add_grid_row(grid, row, "Top Bracket Section:", top_bracket) + + bottom_bracket = QComboBox() + bottom_bracket.addItems(section_options) + apply_field_style(bottom_bracket) + row = self._add_grid_row(grid, row, "Bottom Bracket Section:", bottom_bracket) + + spacing_input = self._create_line_edit("Spacing (mm)") + spacing_input.setValidator(QDoubleValidator(0, 100000, 2)) + self._add_grid_row(grid, row, "Spacing:", spacing_input) + + inputs_layout.addLayout(grid) + inputs_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + left_layout.addWidget(inputs_box) + left_layout.addStretch() + + layout.addWidget(left_column) + + right_column = QWidget() + right_layout = QVBoxLayout(right_column) + right_layout.setContentsMargins(0, 0, 0, 0) + right_layout.setSpacing(10) + + type_box = self._create_inner_box() + type_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + type_layout = QVBoxLayout(type_box) + type_layout.setContentsMargins(12, 8, 12, 10) + type_layout.setSpacing(6) + type_layout.addWidget(self._create_heading_label("Type of Bracing")) + type_layout.addWidget(self._create_image_placeholder("Bracing Layout", 170)) + right_layout.addWidget(type_box) + + for title in ["Bracing", "Top Bracket", "Bottom Bracket"]: + preview_box = self._create_inner_box() + preview_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + preview_layout = QVBoxLayout(preview_box) + preview_layout.setContentsMargins(12, 8, 12, 8) + preview_layout.setSpacing(6) + preview_layout.addWidget(self._create_heading_label(title)) + preview_layout.addWidget(self._create_image_placeholder("Preview", 110)) + right_layout.addWidget(preview_box) + + right_layout.addStretch() + layout.addWidget(right_column) + layout.setStretch(0, 3) + layout.setStretch(1, 4) + return view, type_selector + + def _build_rolled_view(self): + view = self._create_card_frame() + layout = QHBoxLayout(view) + layout.setContentsMargins(12, 12, 12, 12) + layout.setSpacing(12) + + left_column = QWidget() + left_layout = QVBoxLayout(left_column) + left_layout.setContentsMargins(0, 0, 0, 0) + left_layout.setSpacing(8) + left_layout.addWidget(self._create_selection_box()) + + inputs_box = self._create_inner_box() + inputs_layout = QVBoxLayout(inputs_box) + inputs_layout.setContentsMargins(12, 4, 12, 8) + inputs_layout.setSpacing(6) + title = self._create_heading_label("Section Inputs") + title.setStyleSheet("font-size: 12px; font-weight: 600; color: #4b4b4b; border: none; margin-top: 0px; margin-bottom: 2px;") + inputs_layout.addWidget(title) + + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(12) + grid.setVerticalSpacing(8) + grid.setColumnMinimumWidth(0, 130) + grid.setColumnStretch(0, 0) + grid.setColumnStretch(1, 1) + + design_combo = QComboBox() + design_combo.addItems(["Customized", "Optimized"]) + apply_field_style(design_combo) + row = self._add_grid_row(grid, 0, "Design:", design_combo) + + type_selector = QComboBox() + type_selector.addItems(VALUES_END_DIAPHRAGM_TYPE) + type_selector.setCurrentText("Rolled Beam") + apply_field_style(type_selector) + row = self._add_grid_row(grid, row, "Type:", type_selector) + + is_section_combo = QComboBox() + is_section_combo.addItems([ + "ISMB 500", "ISMB 550", "ISMB 600", + "ISWB 500", "ISWB 550", "ISWB 600" + ]) + apply_field_style(is_section_combo) + self._add_grid_row(grid, row, "IS Section:", is_section_combo) + + inputs_layout.addLayout(grid) + inputs_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + left_layout.addWidget(inputs_box) + left_layout.addStretch() + layout.addWidget(left_column) + + right_column = QWidget() + right_layout = QVBoxLayout(right_column) + right_layout.setContentsMargins(0, 0, 0, 0) + right_layout.setSpacing(10) + + image_box = self._create_inner_box() + image_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + image_layout = QVBoxLayout(image_box) + image_layout.setContentsMargins(12, 8, 12, 10) + image_layout.setSpacing(6) + image_layout.addWidget(self._create_heading_label("Dynamic Image")) + image_layout.addWidget(self._create_image_placeholder("Rolled Section", 170)) + right_layout.addWidget(image_box) + + props_box, _ = self._create_section_properties_box("Section Properties:") + props_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + right_layout.addWidget(props_box) + right_layout.addStretch() + + layout.addWidget(right_column) + return view, type_selector + + def _build_welded_view(self): + view = self._create_card_frame() + layout = QHBoxLayout(view) + layout.setContentsMargins(12, 12, 12, 12) + layout.setSpacing(12) + + left_column = QWidget() + left_layout = QVBoxLayout(left_column) + left_layout.setContentsMargins(0, 0, 0, 0) + left_layout.setSpacing(8) + left_layout.addWidget(self._create_selection_box()) + + inputs_box = self._create_inner_box() + inputs_layout = QVBoxLayout(inputs_box) + inputs_layout.setContentsMargins(12, 8, 12, 10) + inputs_layout.setSpacing(8) + inputs_layout.addWidget(self._create_heading_label("Section Inputs:")) + + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(12) + grid.setVerticalSpacing(10) + grid.setColumnMinimumWidth(0, 150) + grid.setColumnStretch(0, 0) + grid.setColumnStretch(1, 1) + + design_combo = QComboBox() + design_combo.addItems(["Customized", "Optimized"]) + apply_field_style(design_combo) + row = self._add_grid_row(grid, 0, "Design:", design_combo) + + type_selector = QComboBox() + type_selector.addItems(VALUES_END_DIAPHRAGM_TYPE) + type_selector.setCurrentText("Welded Beam") + apply_field_style(type_selector) + row = self._add_grid_row(grid, row, "Type:", type_selector) + + symmetry_combo = QComboBox() + symmetry_combo.addItems(["Girder Symmetric", "Girder Unsymmetric"]) + apply_field_style(symmetry_combo) + row = self._add_grid_row(grid, row, "Symmetry:", symmetry_combo) + + total_depth = self._create_line_edit() + row = self._add_grid_row(grid, row, "Total Depth (mm):", total_depth) + + web_thick_combo = QComboBox() + web_thick_combo.addItems(["All", "Custom"]) + apply_field_style(web_thick_combo) + row = self._add_grid_row(grid, row, "Web Thickness (mm):", web_thick_combo) + + top_width = self._create_line_edit() + row = self._add_grid_row(grid, row, "Width of Top Flange (mm):", top_width) + + top_thickness_combo = QComboBox() + top_thickness_combo.addItems(["All", "Custom"]) + apply_field_style(top_thickness_combo) + row = self._add_grid_row(grid, row, "Top Flange Thickness (mm):", top_thickness_combo) + + bottom_width = self._create_line_edit() + row = self._add_grid_row(grid, row, "Width of Bottom Flange (mm):", bottom_width) + + bottom_thickness_combo = QComboBox() + bottom_thickness_combo.addItems(["All", "Custom"]) + apply_field_style(bottom_thickness_combo) + row = self._add_grid_row(grid, row, "Bottom Flange Thickness (mm):", bottom_thickness_combo) + + bearing_thickness = self._create_line_edit() + self._add_grid_row(grid, row, "Bearing Stiffener Thickness (mm):", bearing_thickness) + + inputs_layout.addLayout(grid) + inputs_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + left_layout.addWidget(inputs_box) + left_layout.addStretch() + layout.addWidget(left_column) + + right_column = QWidget() + right_layout = QVBoxLayout(right_column) + right_layout.setContentsMargins(0, 0, 0, 0) + right_layout.setSpacing(10) + + image_box = self._create_inner_box() + image_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + image_layout = QVBoxLayout(image_box) + image_layout.setContentsMargins(12, 8, 12, 10) + image_layout.setSpacing(6) + image_layout.addWidget(self._create_heading_label("Dynamic Image")) + image_layout.addWidget(self._create_image_placeholder("Welded Section", 170)) + right_layout.addWidget(image_box) + + props_box, _ = self._create_section_properties_box("Section Properties:") + props_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + right_layout.addWidget(props_box) + right_layout.addStretch() + + layout.addWidget(right_column) + return view, type_selector + + def _handle_type_selection(self, value): + if self.block_type_sync: + return + if value in self.view_order: + self._set_current_type(value) + + def _set_current_type(self, target): + if target not in self.view_order: + return + if self.current_type == target: + return + self.current_type = target + index = self.view_order.index(target) + self.type_stack.setCurrentIndex(index) + self.block_type_sync = True + for selector in self.type_selectors: + selector.setCurrentText(target) + self.block_type_sync = False + +class CustomVehicleDialog(QDialog): + """Dialog for adding or editing custom live load vehicles""" + + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle("Live Load Custom Vehicle Add/Edit") + self.setModal(True) + self.setMinimumWidth(420) + self.setMinimumHeight(500) + self.setStyleSheet(""" + QDialog { background-color: #ffffff; } + QLabel { color: #2b2b2b; font-size: 11px; background: transparent; } + QLineEdit { + background-color: #ffffff; + border: 1px solid #8a8a8a; + border-radius: 4px; + padding: 4px 8px; + min-height: 24px; + color: #2b2b2b; + } + QLineEdit:focus { border: 1px solid #5a5a5a; } + QLineEdit:read-only { background-color: #f0f0f0; color: #5a5a5a; } + QPushButton { + background-color: #ffffff; + color: #2b2b2b; + border: 1px solid #8a8a8a; + border-radius: 4px; + padding: 5px 12px; + min-width: 50px; + } + QPushButton:hover { background-color: #e8e8e8; } + QPushButton:pressed { background-color: #d8d8d8; } + QTableWidget { + background-color: #ffffff; + border: 1px solid #8a8a8a; + gridline-color: #d0d0d0; + color: #2b2b2b; + } + QTableWidget::item { padding: 4px; } + QHeaderView::section { + background-color: #f0f0f0; + color: #2b2b2b; + border: 1px solid #d0d0d0; + padding: 4px; + font-weight: 600; + } + """) + self.init_ui() + + def init_ui(self): + layout = QVBoxLayout(self) + layout.setContentsMargins(16, 16, 16, 16) + layout.setSpacing(12) + + # Vehicle Name row + name_row = QHBoxLayout() + name_row.setSpacing(10) + name_label = QLabel("Vehicle Name:") + name_label.setStyleSheet("font-weight: 600;") + self.vehicle_name_input = QLineEdit() + self.vehicle_name_input.setFixedWidth(120) + name_row.addWidget(name_label) + name_row.addWidget(self.vehicle_name_input) + name_row.addStretch() + layout.addLayout(name_row) + + # P# D# row with Add/Modify/Delete buttons + pd_button_row = QHBoxLayout() + pd_button_row.setSpacing(8) + + p_label = QLabel("P#") + self.P_input = QLineEdit() + self.P_input.setFixedWidth(50) + pd_button_row.addWidget(p_label) + pd_button_row.addWidget(self.P_input) + + d_label = QLabel("D#") + self.D_input = QLineEdit() + self.D_input.setFixedWidth(50) + pd_button_row.addWidget(d_label) + pd_button_row.addWidget(self.D_input) + + pd_button_row.addStretch() + + self.add_axle_button = QPushButton("Add") + self.modify_axle_button = QPushButton("Modify") + self.delete_axle_button = QPushButton("Delete") + pd_button_row.addWidget(self.add_axle_button) + pd_button_row.addWidget(self.modify_axle_button) + pd_button_row.addWidget(self.delete_axle_button) + + layout.addLayout(pd_button_row) + + # Table and diagram row + table_diagram_row = QHBoxLayout() + table_diagram_row.setSpacing(12) + + # Axle table + self.axle_table = QTableWidget() + self.axle_table.setColumnCount(3) + self.axle_table.setHorizontalHeaderLabels(["No.", "Load (kN)", "Spacing (m)"]) + self.axle_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + self.axle_table.verticalHeader().setVisible(False) + self.axle_table.setMinimumHeight(120) + self.axle_table.setMaximumHeight(140) + table_diagram_row.addWidget(self.axle_table, 1) + + # Axle diagram placeholder + axle_diagram = QLabel("Axle Layout Diagram") + axle_diagram.setAlignment(Qt.AlignCenter) + axle_diagram.setMinimumHeight(120) + axle_diagram.setStyleSheet(""" + QLabel { + border: 1px solid #8a8a8a; + border-radius: 4px; + background: #ffffff; + color: #6a6a6a; + font-size: 10px; + } + """) + table_diagram_row.addWidget(axle_diagram, 1) + + layout.addLayout(table_diagram_row) + + # Input fields grid + fields_grid = QGridLayout() + fields_grid.setContentsMargins(0, 8, 0, 0) + fields_grid.setHorizontalSpacing(12) + fields_grid.setVerticalSpacing(10) + fields_grid.setColumnMinimumWidth(0, 240) + + field_labels = [ + "Minimum nose to tail distance (m):", + "Width of Wheel, w (mm):", + "Minimum Clearance from Carriageway\nEdge, f (mm):", + "Minimum Clearance from Crossing Vehicles,\ng (mm):", + "Wheel Spacing in Transverse Direction (m):", + "Impact Factor:", + ] + + self.custom_fields = {} + for row, text in enumerate(field_labels): + lbl = QLabel(text) + field = QLineEdit() + if "Impact" in text: + field.setText("0.25") + field.setReadOnly(True) + field.setFixedWidth(100) + fields_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + fields_grid.addWidget(field, row, 1, Qt.AlignLeft | Qt.AlignVCenter) + self.custom_fields[text] = field + + layout.addLayout(fields_grid) + + # Bottom diagram - Clear Carriageway Width + bottom_diagram_label = QLabel("CLEAR CARRIAGEWAY WIDTH") + bottom_diagram_label.setAlignment(Qt.AlignCenter) + bottom_diagram_label.setStyleSheet("font-size: 9px; font-weight: 600; color: #5a5a5a; background: transparent;") + layout.addWidget(bottom_diagram_label) + + bottom_diagram = QLabel("") + bottom_diagram.setAlignment(Qt.AlignCenter) + bottom_diagram.setMinimumHeight(80) + bottom_diagram.setStyleSheet(""" + QLabel { + border: 1px solid #8a8a8a; + border-radius: 4px; + background: #ffffff; + } + """) + layout.addWidget(bottom_diagram) + + layout.addStretch() + +class LoadingTab(QWidget): + """Loading tab with permanent load layout and load-type subtabs""" + + def __init__(self, parent=None): + super().__init__(parent) + self.custom_vehicle_dialog = CustomVehicleDialog(self) + self.init_ui() + + def init_ui(self): + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + self.load_tabs = QTabWidget() + self.load_tabs.setDocumentMode(True) + self.load_tabs.setStyleSheet( + "QTabWidget::pane { border: none; background: #f5f5f5; }" + "QTabBar::tab { background: #e8e8e8; color: #4b4b4b; border: 1px solid #cfcfcf;" + " border-bottom: none; padding: 8px 20px; margin-right: 2px; min-width: 120px;" + " font-size: 11px; border-top-left-radius: 6px; border-top-right-radius: 6px; }" + "QTabBar::tab:selected { background: #9ecb3d; color: #ffffff; font-weight: bold; }" + "QTabBar::tab:!selected { margin-top: 2px; }" + ) + + self.load_tabs.addTab(self._build_permanent_load_tab(), "Permanent Load") + self.load_tabs.addTab(self._build_live_load_tab(), "Live Load") + self.load_tabs.addTab(self._build_seismic_load_tab(), "Seismic Load") + self.load_tabs.addTab(self._build_wind_load_tab(), "Wind Load") + self.load_tabs.addTab(self._build_temperature_load_tab(), "Temperature Load") + self.load_tabs.addTab(self._create_placeholder_page("Custom Load"), "Custom Load") + self.load_tabs.addTab(self._build_load_combination_tab(), "Load Combination") + main_layout.addWidget(self.load_tabs) + + def _build_permanent_load_tab(self): + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + page_layout = QVBoxLayout(page) + page_layout.setContentsMargins(12, 12, 12, 12) + page_layout.setSpacing(12) + + content_row = QHBoxLayout() + content_row.setContentsMargins(0, 0, 0, 0) + content_row.setSpacing(16) + + left_card = self._create_card() + left_card.setStyleSheet( + "QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }" + ) + left_layout = QVBoxLayout(left_card) + left_layout.setContentsMargins(16, 16, 16, 16) + left_layout.setSpacing(16) + + self._add_load_section(left_layout, "Dead Load (DL):", [ + ("Include Member Self Weight:", self._create_yes_no_combo()), + ("Self-weight factor:", self._create_line_edit()), + ("Include Concrete Deck Weight:", self._create_yes_no_combo()), + ]) + + self._add_load_section(left_layout, "Dead Load for Surfacing (DW):", [ + ("Include Load from Wearing Course:", self._create_yes_no_combo()), + ]) + + self._add_load_section(left_layout, "Super-Imposed Dead Load (SIDL):", [ + ("Include Load from Crash Barrier:", self._create_yes_no_combo()), + ("Include Load from Median:", self._create_yes_no_combo()), + ("Include Load from Railing:", self._create_yes_no_combo()), + ]) + + left_layout.addStretch() + + right_card = self._create_card() + right_card.setStyleSheet( + "QFrame { border: 1px solid #9c9c9c; border-radius: 10px; background-color: #c8c8c8; }" + ) + right_card.setMinimumWidth(270) + right_card.setMinimumHeight(360) + right_layout = QVBoxLayout(right_card) + right_layout.setContentsMargins(18, 18, 18, 18) + right_layout.setSpacing(12) + description_label = QLabel("Description Box") + description_label.setAlignment(Qt.AlignCenter) + description_label.setStyleSheet("font-size: 12px; font-weight: 700; color: #000000;") + description_label.setMinimumHeight(320) + right_layout.addWidget(description_label) + + content_row.addWidget(left_card, 3) + content_row.addWidget(right_card, 2) + + page_layout.addLayout(content_row) + page_layout.addSpacing(4) + return page + + def _build_live_load_tab(self): + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + page_layout = QVBoxLayout(page) + page_layout.setContentsMargins(12, 12, 12, 12) + page_layout.setSpacing(12) + + content_row = QHBoxLayout() + content_row.setContentsMargins(0, 0, 0, 0) + content_row.setSpacing(16) + + left_card = self._create_card() + left_card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + left_layout = QVBoxLayout(left_card) + left_layout.setContentsMargins(14, 14, 14, 14) + left_layout.setSpacing(8) + + # Title without box + title = QLabel("Live Load (LL) Inputs:") + title.setStyleSheet("font-size: 12px; font-weight: 700; color: #3a3a3a; background: transparent; border: none;") + left_layout.addWidget(title) + + irc_vehicles = [ + "Class A", "Class 70R Wheeled", "Class 70R Tracked", + "Class AA Wheeled", "Class AA Tracked", "Class SV", "Fatigue Truck" + ] + self._add_checkbox_section(left_layout, "Vehicles from IRC 6:", irc_vehicles) + + # Custom Vehicle header with Add/Edit buttons + custom_header = QHBoxLayout() + custom_header.setSpacing(8) + custom_label = QLabel("Custom Vehicle:") + custom_label.setStyleSheet("font-size: 12px; font-weight: 700; color: #3a3a3a; background: transparent; border: none;") + custom_header.addWidget(custom_label) + custom_header.addStretch() + self.custom_vehicle_add_button = QPushButton("Add") + self.custom_vehicle_edit_button = QPushButton("Edit") + for btn in (self.custom_vehicle_add_button, self.custom_vehicle_edit_button): + btn.setFixedWidth(50) + btn.setStyleSheet( + "QPushButton { background: #ffffff; color: #2f2f2f; border: 1px solid #7a7a7a; border-radius: 4px; padding: 4px 10px; }" + "QPushButton:hover { background: #f0f0f0; }" + "QPushButton:pressed { background: #e0e0e0; }" + ) + custom_header.addWidget(btn) + left_layout.addLayout(custom_header) + + # Vehicle Name 1 and 2 as simple checkbox rows (like reference image 2) + self.custom_vehicle_checkboxes = [] + for index in range(2): + row_layout = QHBoxLayout() + row_layout.setContentsMargins(0, 0, 0, 0) + row_layout.setSpacing(8) + label = QLabel(f"Vehicle Name {index + 1}") + label.setStyleSheet("font-size: 11px; font-style: italic; color: #4b4b4b; background: transparent; border: none;") + checkbox = QCheckBox() + checkbox.setChecked(False) + row_layout.addWidget(label) + row_layout.addStretch() + row_layout.addWidget(checkbox) + left_layout.addLayout(row_layout) + self.custom_vehicle_checkboxes.append(checkbox) + + # Braking Load from Vehicles section - includes IRC vehicles + Vehicle Name 1/2 + braking_vehicles = irc_vehicles + ["Vehicle Name 1", "Vehicle Name 2"] + self._add_checkbox_section(left_layout, "Braking Load from Vehicles:", braking_vehicles) + + # Bottom inputs with aligned widths + input_width = 120 + + # Eccentricity row + ecc_row = QHBoxLayout() + ecc_row.setSpacing(10) + ecc_label = QLabel("Eccentricity from top of Deck (m):") + ecc_label.setStyleSheet("font-size: 11px; font-weight: 600; color: #3a3a3a; background: transparent; border: none;") + ecc_label.setMinimumWidth(200) + self.eccentricity_input = QLineEdit() + self.eccentricity_input.setFixedWidth(input_width) + apply_field_style(self.eccentricity_input) + ecc_row.addWidget(ecc_label) + ecc_row.addWidget(self.eccentricity_input) + ecc_row.addStretch() + left_layout.addLayout(ecc_row) + + # Footpath Pressure row with dropdown + footpath_row = QHBoxLayout() + footpath_row.setSpacing(10) + footpath_label = QLabel("Footpath Pressure (kN/mm2 ):") + footpath_label.setStyleSheet("font-size: 11px; font-weight: 600; color: #3a3a3a; background: transparent; border: none;") + footpath_label.setMinimumWidth(200) + self.footpath_mode_combo = QComboBox() + self.footpath_mode_combo.addItems(["Automatic", "User-defined"]) + self.footpath_mode_combo.setFixedWidth(input_width) + apply_field_style(self.footpath_mode_combo) + footpath_row.addWidget(footpath_label) + footpath_row.addWidget(self.footpath_mode_combo) + footpath_row.addStretch() + left_layout.addLayout(footpath_row) + + # Value input below footpath (aligned with dropdown above) + value_row = QHBoxLayout() + value_row.setContentsMargins(0, 0, 0, 0) + value_row.setSpacing(10) + value_spacer = QLabel("") + value_spacer.setMinimumWidth(200) + self.footpath_value_input = QLineEdit() + self.footpath_value_input.setPlaceholderText("Value") + self.footpath_value_input.setFixedWidth(input_width) + apply_field_style(self.footpath_value_input) + value_row.addWidget(value_spacer) + value_row.addWidget(self.footpath_value_input) + value_row.addStretch() + left_layout.addLayout(value_row) + + left_layout.addStretch() + + # Right description card + right_card = self._create_card() + right_card.setStyleSheet("QFrame { border: 1px solid #9c9c9c; border-radius: 10px; background-color: #d4d4d4; }") + right_card.setMinimumWidth(260) + right_card.setMinimumHeight(420) + right_layout = QVBoxLayout(right_card) + right_layout.setContentsMargins(16, 16, 16, 16) + right_layout.setSpacing(10) + + # Description Box title - no box around it + desc_label = QLabel("Description Box") + desc_label.setAlignment(Qt.AlignCenter) + desc_label.setStyleSheet("font-size: 12px; font-weight: 700; color: #000000; background: transparent; border: none;") + right_layout.addWidget(desc_label) + + description_text = ( + "211.2 The braking effect on a simply supported span or a continuous unit of spans " + "or on any other type of bridge unit shall be assumed to have the following value:\n\n" + "a) In the case of a single lane or a two lane bridge: twenty percent of the first train " + "load plus ten percent of the load of the succeeding trains or part thereof, the train " + "loads in one lane only being considered for the purpose of this subclause. Where the " + "entire first train is not on the full span, the braking force shall be taken as equal to " + "twenty percent of the loads actually on the span or continuous unit of spans.\n" + "b) In the case of bridges having more than two lanes: as in (a) above for the first two " + "lanes plus five percent of the loads on the lanes in excess of two." + ) + description_label = QLabel(description_text) + description_label.setWordWrap(True) + description_label.setStyleSheet("font-size: 11px; color: #4b4b4b; background: transparent; border: none;") + right_layout.addWidget(description_label) + right_layout.addStretch() + + content_row.addWidget(left_card, 3) + content_row.addWidget(right_card, 2) + page_layout.addLayout(content_row) + page_layout.addSpacing(4) + + self.custom_vehicle_add_button.clicked.connect(self.show_custom_vehicle_dialog) + self.custom_vehicle_edit_button.clicked.connect(self.show_custom_vehicle_dialog) + self.footpath_mode_combo.currentTextChanged.connect(self._on_footpath_mode_changed) + self._on_footpath_mode_changed(self.footpath_mode_combo.currentText()) + + return page + + def _build_seismic_load_tab(self): + """Build the Seismic/Earthquake Load tab matching reference design""" + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + page_layout = QVBoxLayout(page) + page_layout.setContentsMargins(12, 12, 12, 12) + page_layout.setSpacing(12) + + content_row = QHBoxLayout() + content_row.setContentsMargins(0, 0, 0, 0) + content_row.setSpacing(16) + + # Left card with inputs + left_card = self._create_card() + left_card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + left_layout = QVBoxLayout(left_card) + left_layout.setContentsMargins(16, 16, 16, 16) + left_layout.setSpacing(12) + + # Title + title = QLabel("Seismic/Earthquake Load (EL) Inputs for Evaluation per IRC 6") + title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + left_layout.addWidget(title) + + label_style = "font-size: 11px; color: #3a3a3a; background: transparent; border: none;" + field_width = 120 + + # ===== Seismic Inputs Box ===== + seismic_inputs_box = QFrame() + seismic_inputs_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + seismic_inputs_layout = QGridLayout(seismic_inputs_box) + seismic_inputs_layout.setContentsMargins(12, 12, 12, 12) + seismic_inputs_layout.setHorizontalSpacing(12) + seismic_inputs_layout.setVerticalSpacing(10) + seismic_inputs_layout.setColumnMinimumWidth(0, 200) + + row = 0 + + # Seismic Zone + lbl = QLabel("Seismic Zone:") + lbl.setStyleSheet(label_style) + self.seismic_zone_combo = QComboBox() + self.seismic_zone_combo.addItems(["II", "III", "IV", "V"]) + self.seismic_zone_combo.setFixedWidth(field_width) + apply_field_style(self.seismic_zone_combo) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.seismic_zone_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Importance Factor + lbl = QLabel("Importance Factor:") + lbl.setStyleSheet(label_style) + self.importance_factor_input = QLineEdit() + self.importance_factor_input.setText("1") + self.importance_factor_input.setFixedWidth(field_width) + apply_field_style(self.importance_factor_input) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.importance_factor_input, row, 1, Qt.AlignLeft) + row += 1 + + # Type of Soil + lbl = QLabel("Type of Soil:") + lbl.setStyleSheet(label_style) + self.soil_type_combo = QComboBox() + self.soil_type_combo.addItems([ + "Type I – Rocky or Hard Soil Sites (N>30)", + "Type II – Medium Soil Sites", + "Type III – Soft Soil Sites" + ]) + self.soil_type_combo.setFixedWidth(field_width + 30) + apply_field_style(self.soil_type_combo) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.soil_type_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Time Period + lbl = QLabel("Time Period:") + lbl.setStyleSheet(label_style) + self.time_period_input = QLineEdit() + self.time_period_input.setFixedWidth(field_width) + apply_field_style(self.time_period_input) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.time_period_input, row, 1, Qt.AlignLeft) + row += 1 + + # Damping Percentage + lbl = QLabel("Damping Percentage:") + lbl.setStyleSheet(label_style) + self.damping_input = QLineEdit() + self.damping_input.setText("2") + self.damping_input.setFixedWidth(field_width) + apply_field_style(self.damping_input) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.damping_input, row, 1, Qt.AlignLeft) + row += 1 + + # Response Reduction Factor + lbl = QLabel("Response Reduction Factor:") + lbl.setStyleSheet(label_style) + self.response_factor_combo = QComboBox() + self.response_factor_combo.addItems(["1", "2", "3", "4", "5"]) + self.response_factor_combo.setCurrentText("1") + self.response_factor_combo.setFixedWidth(field_width) + apply_field_style(self.response_factor_combo) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.response_factor_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Dead Load for Seismic Force + lbl = QLabel("Dead Load for Seismic Force (kN):") + lbl.setStyleSheet(label_style) + self.dead_load_seismic_combo = QComboBox() + self.dead_load_seismic_combo.addItems(["Automatic", "Custom"]) + self.dead_load_seismic_combo.setFixedWidth(field_width) + apply_field_style(self.dead_load_seismic_combo) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.dead_load_seismic_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Custom Value for Dead Load + self.dead_load_custom_input = QLineEdit() + self.dead_load_custom_input.setPlaceholderText("Custom Value") + self.dead_load_custom_input.setFixedWidth(field_width) + self.dead_load_custom_input.setEnabled(False) + apply_field_style(self.dead_load_custom_input) + seismic_inputs_layout.addWidget(self.dead_load_custom_input, row, 1, Qt.AlignLeft) + row += 1 + + # Live Load for Seismic Force + lbl = QLabel("Live Load for Seismic Force (kN):") + lbl.setStyleSheet(label_style) + self.live_load_seismic_combo = QComboBox() + self.live_load_seismic_combo.addItems(["Automatic", "Custom"]) + self.live_load_seismic_combo.setFixedWidth(field_width) + apply_field_style(self.live_load_seismic_combo) + seismic_inputs_layout.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + seismic_inputs_layout.addWidget(self.live_load_seismic_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Custom Value for Live Load + self.live_load_custom_input = QLineEdit() + self.live_load_custom_input.setPlaceholderText("Custom Value") + self.live_load_custom_input.setFixedWidth(field_width) + self.live_load_custom_input.setEnabled(False) + apply_field_style(self.live_load_custom_input) + seismic_inputs_layout.addWidget(self.live_load_custom_input, row, 1, Qt.AlignLeft) + + left_layout.addWidget(seismic_inputs_box) + + # ===== Computed Values Box ===== + computed_box = QFrame() + computed_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + computed_layout = QGridLayout(computed_box) + computed_layout.setContentsMargins(12, 12, 12, 12) + computed_layout.setHorizontalSpacing(12) + computed_layout.setVerticalSpacing(10) + computed_layout.setColumnMinimumWidth(0, 200) + + computed_fields = [ + ("Zone Factor:", "zone_factor"), + ("Spectral Acceleration Coefficient:", "spectral_coeff"), + ("Horizontal Seismic Coefficient:", "horizontal_coeff"), + ("Vertical Seismic Coefficient:", "vertical_coeff"), + ] + + self.seismic_computed_fields = {} + for idx, (label_text, field_name) in enumerate(computed_fields): + lbl = QLabel(label_text) + lbl.setStyleSheet(label_style) + field = QLineEdit() + field.setFixedWidth(field_width) + field.setReadOnly(True) + apply_field_style(field) + computed_layout.addWidget(lbl, idx, 0, Qt.AlignLeft | Qt.AlignVCenter) + computed_layout.addWidget(field, idx, 1, Qt.AlignLeft) + self.seismic_computed_fields[field_name] = field + + left_layout.addWidget(computed_box) + left_layout.addStretch() + + # Right description card + right_card = self._create_card() + right_card.setStyleSheet("QFrame { border: 1px solid #9c9c9c; border-radius: 10px; background-color: #d4d4d4; }") + right_card.setMinimumWidth(200) + right_card.setMinimumHeight(400) + right_layout = QVBoxLayout(right_card) + right_layout.setContentsMargins(16, 16, 16, 16) + right_layout.setSpacing(10) + + desc_title = QLabel("Description Box") + desc_title.setAlignment(Qt.AlignCenter) + desc_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + right_layout.addWidget(desc_title) + + desc_text = QLabel("Importance factor for normal, important, and critical bridges.") + desc_text.setWordWrap(True) + desc_text.setStyleSheet("font-size: 11px; color: #4b4b4b; background: transparent; border: none;") + right_layout.addWidget(desc_text) + right_layout.addStretch() + + content_row.addWidget(left_card, 3) + content_row.addWidget(right_card, 2) + + page_layout.addLayout(content_row) + + # Connect signals for enabling/disabling custom inputs + self.dead_load_seismic_combo.currentTextChanged.connect(self._on_dead_load_mode_changed) + self.live_load_seismic_combo.currentTextChanged.connect(self._on_live_load_mode_changed) + + return page + + def _on_dead_load_mode_changed(self, mode): + is_custom = mode == "Custom" + self.dead_load_custom_input.setEnabled(is_custom) + if not is_custom: + self.dead_load_custom_input.clear() + + def _on_live_load_mode_changed(self, mode): + is_custom = mode == "Custom" + self.live_load_custom_input.setEnabled(is_custom) + if not is_custom: + self.live_load_custom_input.clear() + + def _add_load_section(self, parent_layout, title, rows): + title_label = QLabel(title) + title_label.setStyleSheet("font-size: 12px; font-weight: 600; color: #3e3e3e; background: transparent; border: none;") + parent_layout.addWidget(title_label) + + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(12) + grid.setVerticalSpacing(12) + grid.setColumnMinimumWidth(0, 230) + grid.setColumnStretch(0, 0) + grid.setColumnStretch(1, 1) + + field_width = 170 + + for row_index, (label_text, widget) in enumerate(rows): + label = QLabel(label_text) + label.setStyleSheet("font-size: 11px; color: #4b4b4b; background: transparent; border: none;") + grid.addWidget(label, row_index, 0, Qt.AlignLeft | Qt.AlignVCenter) + widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + if isinstance(widget, QComboBox): + widget.setFixedWidth(field_width) + elif isinstance(widget, QLineEdit): + widget.setFixedWidth(field_width) + grid.addWidget(widget, row_index, 1) + + parent_layout.addLayout(grid) + + def _add_checkbox_section(self, parent_layout, title, items): + title_label = QLabel(title) + title_label.setStyleSheet("font-size: 12px; font-weight: 600; color: #3e3e3e; background: transparent; border: none;") + parent_layout.addWidget(title_label) + + grid = QGridLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setHorizontalSpacing(12) + grid.setVerticalSpacing(8) + grid.setColumnStretch(0, 1) + + + for row, name in enumerate(items): + label = QLabel(name) + # Make Vehicle Name entries italic + if "Vehicle Name" in name: + label.setStyleSheet("font-size: 11px; font-style: italic; color: #4b4b4b; background: transparent; border: none; padding: 0px;") + else: + label.setStyleSheet("font-size: 11px; color: #4b4b4b; background: transparent; border: none; padding: 0px;") + checkbox = QCheckBox() + checkbox.setChecked(False) + grid.addWidget(label, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + grid.addWidget(checkbox, row, 1, Qt.AlignRight | Qt.AlignVCenter) + + parent_layout.addLayout(grid) + + def _on_footpath_mode_changed(self, mode): + is_custom = mode == "User-defined" + self.footpath_value_input.setEnabled(is_custom) + if not is_custom: + self.footpath_value_input.clear() + + def show_custom_vehicle_dialog(self): + self.custom_vehicle_dialog.show() + self.custom_vehicle_dialog.raise_() + self.custom_vehicle_dialog.activateWindow() + + def _create_yes_no_combo(self): + combo = QComboBox() + combo.addItems(VALUES_YES_NO) + combo.setCurrentText("Yes") + apply_field_style(combo) + return combo + + def _create_line_edit(self): + line_edit = QLineEdit() + apply_field_style(line_edit) + return line_edit + + def _create_card(self): + card = QFrame() + card.setStyleSheet("QFrame { border: 1px solid #cfcfcf; border-radius: 12px; background-color: #ffffff; }") + return card + + def _build_wind_load_tab(self): + """Build the Wind Load tab matching reference design""" + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + page_layout = QVBoxLayout(page) + page_layout.setContentsMargins(12, 12, 12, 12) + page_layout.setSpacing(12) + + content_row = QHBoxLayout() + content_row.setContentsMargins(0, 0, 0, 0) + content_row.setSpacing(16) + + # Left card with inputs - use scroll area for many fields + left_card = self._create_card() + left_card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + left_card_layout = QVBoxLayout(left_card) + left_card_layout.setContentsMargins(0, 0, 0, 0) + left_card_layout.setSpacing(0) + + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setStyleSheet( + "QScrollArea { border: none; background: transparent; }" + "QScrollArea > QWidget > QWidget { background: transparent; }" + ) + + scroll_content = QWidget() + scroll_content.setStyleSheet("background: #ffffff;") + left_layout = QVBoxLayout(scroll_content) + left_layout.setContentsMargins(16, 16, 16, 16) + left_layout.setSpacing(12) + + label_style = "font-size: 11px; color: #3a3a3a; background: transparent; border: none;" + field_width = 120 + + # ===== Wind Load Inputs Box ===== + wind_inputs_box = QFrame() + wind_inputs_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + wind_inputs_layout = QVBoxLayout(wind_inputs_box) + wind_inputs_layout.setContentsMargins(12, 12, 12, 12) + wind_inputs_layout.setSpacing(10) + + wind_title = QLabel("Wind Load (WL) Inputs for Evaluation per IRC6") + wind_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + wind_inputs_layout.addWidget(wind_title) + + wind_grid = QGridLayout() + wind_grid.setContentsMargins(0, 4, 0, 0) + wind_grid.setHorizontalSpacing(12) + wind_grid.setVerticalSpacing(8) + wind_grid.setColumnMinimumWidth(0, 220) + + row = 0 + + # Basic Wind Speed + lbl = QLabel("Basic Wind Speed (m/s):") + lbl.setStyleSheet(label_style) + self.basic_wind_speed_input = QLineEdit() + self.basic_wind_speed_input.setFixedWidth(field_width) + apply_field_style(self.basic_wind_speed_input) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.basic_wind_speed_input, row, 1, Qt.AlignLeft) + row += 1 + + # Average Exposed Height + lbl = QLabel("Average Exposed Height (m):") + lbl.setStyleSheet(label_style) + self.avg_exposed_height_input = QLineEdit() + self.avg_exposed_height_input.setFixedWidth(field_width) + apply_field_style(self.avg_exposed_height_input) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.avg_exposed_height_input, row, 1, Qt.AlignLeft) + row += 1 + + # Type of Terrain + lbl = QLabel("Type of Terrain:") + lbl.setStyleSheet(label_style) + self.terrain_type_combo = QComboBox() + self.terrain_type_combo.addItems(["Plain", "Hilly", "Coastal"]) + self.terrain_type_combo.setFixedWidth(field_width) + apply_field_style(self.terrain_type_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.terrain_type_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Site Topography + lbl = QLabel("Site Topography:") + lbl.setStyleSheet(label_style) + self.site_topography_combo = QComboBox() + self.site_topography_combo.addItems(["Flat", "Hilly", "Ridge", "Valley"]) + self.site_topography_combo.setFixedWidth(field_width) + apply_field_style(self.site_topography_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.site_topography_combo, row, 1, Qt.AlignLeft) + row += 1 + + # Gust Factor, G + lbl = QLabel("Gust Factor, G:") + lbl.setStyleSheet(label_style) + self.gust_factor_combo = QComboBox() + self.gust_factor_combo.addItems(["Automatic", "Custom"]) + self.gust_factor_combo.setFixedWidth(field_width) + apply_field_style(self.gust_factor_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.gust_factor_combo, row, 1, Qt.AlignLeft) + row += 1 + self.gust_factor_value = QLineEdit() + self.gust_factor_value.setPlaceholderText("Value") + self.gust_factor_value.setFixedWidth(field_width) + self.gust_factor_value.setEnabled(False) + apply_field_style(self.gust_factor_value) + wind_grid.addWidget(self.gust_factor_value, row, 1, Qt.AlignLeft) + row += 1 + + # Drag Coefficient, CD + lbl = QLabel("Drag Coefficient, CD:") + lbl.setStyleSheet(label_style) + self.drag_coeff_combo = QComboBox() + self.drag_coeff_combo.addItems(["Automatic", "Custom"]) + self.drag_coeff_combo.setFixedWidth(field_width) + apply_field_style(self.drag_coeff_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.drag_coeff_combo, row, 1, Qt.AlignLeft) + row += 1 + self.drag_coeff_value = QLineEdit() + self.drag_coeff_value.setPlaceholderText("Custom Value") + self.drag_coeff_value.setFixedWidth(field_width) + self.drag_coeff_value.setEnabled(False) + apply_field_style(self.drag_coeff_value) + wind_grid.addWidget(self.drag_coeff_value, row, 1, Qt.AlignLeft) + row += 1 + + # Drag Coefficient against Live Load, CDLL + lbl = QLabel("Drag Coefficient against Live Load, CDLL:") + lbl.setStyleSheet(label_style) + self.drag_coeff_ll_combo = QComboBox() + self.drag_coeff_ll_combo.addItems(["Automatic", "Custom"]) + self.drag_coeff_ll_combo.setFixedWidth(field_width) + apply_field_style(self.drag_coeff_ll_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.drag_coeff_ll_combo, row, 1, Qt.AlignLeft) + row += 1 + self.drag_coeff_ll_value = QLineEdit() + self.drag_coeff_ll_value.setPlaceholderText("Value") + self.drag_coeff_ll_value.setFixedWidth(field_width) + self.drag_coeff_ll_value.setEnabled(False) + apply_field_style(self.drag_coeff_ll_value) + wind_grid.addWidget(self.drag_coeff_ll_value, row, 1, Qt.AlignLeft) + row += 1 + + # Lift Coefficient, CL + lbl = QLabel("Lift Coefficient, CL:") + lbl.setStyleSheet(label_style) + self.lift_coeff_combo = QComboBox() + self.lift_coeff_combo.addItems(["Automatic", "Custom"]) + self.lift_coeff_combo.setFixedWidth(field_width) + apply_field_style(self.lift_coeff_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.lift_coeff_combo, row, 1, Qt.AlignLeft) + row += 1 + self.lift_coeff_value = QLineEdit() + self.lift_coeff_value.setPlaceholderText("Value") + self.lift_coeff_value.setFixedWidth(field_width) + self.lift_coeff_value.setEnabled(False) + apply_field_style(self.lift_coeff_value) + wind_grid.addWidget(self.lift_coeff_value, row, 1, Qt.AlignLeft) + row += 1 + + # Superstructure Area in Elevation + lbl = QLabel("Superstructure Area in Elevation (m2):") + lbl.setStyleSheet(label_style) + self.super_area_elev_combo = QComboBox() + self.super_area_elev_combo.addItems(["Automatic", "Custom"]) + self.super_area_elev_combo.setFixedWidth(field_width) + apply_field_style(self.super_area_elev_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.super_area_elev_combo, row, 1, Qt.AlignLeft) + row += 1 + self.super_area_elev_value = QLineEdit() + self.super_area_elev_value.setPlaceholderText("Custom Value") + self.super_area_elev_value.setFixedWidth(field_width) + self.super_area_elev_value.setEnabled(False) + apply_field_style(self.super_area_elev_value) + wind_grid.addWidget(self.super_area_elev_value, row, 1, Qt.AlignLeft) + row += 1 + + # Superstructure Area in Plain + lbl = QLabel("Superstructure Area in Plain (m2):") + lbl.setStyleSheet(label_style) + self.super_area_plain_combo = QComboBox() + self.super_area_plain_combo.addItems(["Automatic", "Custom"]) + self.super_area_plain_combo.setFixedWidth(field_width) + apply_field_style(self.super_area_plain_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.super_area_plain_combo, row, 1, Qt.AlignLeft) + row += 1 + self.super_area_plain_value = QLineEdit() + self.super_area_plain_value.setPlaceholderText("Custom Value") + self.super_area_plain_value.setFixedWidth(field_width) + self.super_area_plain_value.setEnabled(False) + apply_field_style(self.super_area_plain_value) + wind_grid.addWidget(self.super_area_plain_value, row, 1, Qt.AlignLeft) + row += 1 + + # Exposed Frontal Area of Live Load + lbl = QLabel("Exposed Frontal Area of Live Load (m2):") + lbl.setStyleSheet(label_style) + self.exposed_frontal_area_combo = QComboBox() + self.exposed_frontal_area_combo.addItems(["Automatic", "Custom"]) + self.exposed_frontal_area_combo.setFixedWidth(field_width) + apply_field_style(self.exposed_frontal_area_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.exposed_frontal_area_combo, row, 1, Qt.AlignLeft) + row += 1 + self.exposed_frontal_area_value = QLineEdit() + self.exposed_frontal_area_value.setPlaceholderText("Custom Value") + self.exposed_frontal_area_value.setFixedWidth(field_width) + self.exposed_frontal_area_value.setEnabled(False) + apply_field_style(self.exposed_frontal_area_value) + wind_grid.addWidget(self.exposed_frontal_area_value, row, 1, Qt.AlignLeft) + row += 1 + + # Wind Load Eccentricity from Top of Deck + lbl = QLabel("Wind Load Eccentricity from Top of Deck\n(m): Negative for below deck") + lbl.setStyleSheet(label_style) + self.wind_ecc_deck_combo = QComboBox() + self.wind_ecc_deck_combo.addItems(["Automatic", "Custom"]) + self.wind_ecc_deck_combo.setFixedWidth(field_width) + apply_field_style(self.wind_ecc_deck_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.wind_ecc_deck_combo, row, 1, Qt.AlignLeft) + row += 1 + self.wind_ecc_deck_value = QLineEdit() + self.wind_ecc_deck_value.setPlaceholderText("Value") + self.wind_ecc_deck_value.setFixedWidth(field_width) + self.wind_ecc_deck_value.setEnabled(False) + apply_field_style(self.wind_ecc_deck_value) + wind_grid.addWidget(self.wind_ecc_deck_value, row, 1, Qt.AlignLeft) + row += 1 + + # Wind on Live Load Eccentricity from Top of Deck + lbl = QLabel("Wind on Live Load Eccentricity from Top\nof Deck (m):") + lbl.setStyleSheet(label_style) + self.wind_ll_ecc_combo = QComboBox() + self.wind_ll_ecc_combo.addItems(["Automatic", "Custom"]) + self.wind_ll_ecc_combo.setFixedWidth(field_width) + apply_field_style(self.wind_ll_ecc_combo) + wind_grid.addWidget(lbl, row, 0, Qt.AlignLeft | Qt.AlignVCenter) + wind_grid.addWidget(self.wind_ll_ecc_combo, row, 1, Qt.AlignLeft) + row += 1 + self.wind_ll_ecc_value = QLineEdit() + self.wind_ll_ecc_value.setPlaceholderText("Value") + self.wind_ll_ecc_value.setFixedWidth(field_width) + self.wind_ll_ecc_value.setEnabled(False) + apply_field_style(self.wind_ll_ecc_value) + wind_grid.addWidget(self.wind_ll_ecc_value, row, 1, Qt.AlignLeft) + + wind_inputs_layout.addLayout(wind_grid) + left_layout.addWidget(wind_inputs_box) + + # ===== Computed Values Box ===== + computed_box = QFrame() + computed_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + computed_layout = QGridLayout(computed_box) + computed_layout.setContentsMargins(12, 12, 12, 12) + computed_layout.setHorizontalSpacing(12) + computed_layout.setVerticalSpacing(8) + computed_layout.setColumnMinimumWidth(0, 220) + + computed_fields = [ + ("Hourly Mean Wind Speed (m/s):", "hourly_mean_wind"), + ("Hourly Wind Pressure in N/m2:", "hourly_wind_pressure"), + ("Transverse Wind Force in N:", "transverse_wind_force"), + ("Longitudinal Wind Force in N:", "longitudinal_wind_force"), + ("Vertical Wind Force in N:", "vertical_wind_force"), + ("Transverse Wind Force on Live\nLoad in N:", "transverse_wind_ll"), + ("Longitudinal Wind Force on Live\nLoad in N:", "longitudinal_wind_ll"), + ] + + self.wind_computed_fields = {} + for idx, (label_text, field_name) in enumerate(computed_fields): + lbl = QLabel(label_text) + lbl.setStyleSheet(label_style) + field = QLineEdit() + field.setFixedWidth(field_width) + field.setReadOnly(True) + apply_field_style(field) + computed_layout.addWidget(lbl, idx, 0, Qt.AlignLeft | Qt.AlignVCenter) + computed_layout.addWidget(field, idx, 1, Qt.AlignLeft) + self.wind_computed_fields[field_name] = field + + left_layout.addWidget(computed_box) + left_layout.addStretch() + + scroll.setWidget(scroll_content) + left_card_layout.addWidget(scroll) + + # Right description card + right_card = self._create_card() + right_card.setStyleSheet("QFrame { border: 1px solid #9c9c9c; border-radius: 10px; background-color: #d4d4d4; }") + right_card.setMinimumWidth(150) + right_card.setMaximumWidth(200) + right_layout = QVBoxLayout(right_card) + right_layout.setContentsMargins(16, 16, 16, 16) + right_layout.setSpacing(10) + + desc_title = QLabel("Description\nBox") + desc_title.setAlignment(Qt.AlignCenter) + desc_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + right_layout.addWidget(desc_title) + right_layout.addStretch() + + content_row.addWidget(left_card, 3) + content_row.addWidget(right_card, 1) + + page_layout.addLayout(content_row) + + # Connect signals for enabling/disabling custom inputs + self.gust_factor_combo.currentTextChanged.connect(lambda t: self.gust_factor_value.setEnabled(t == "Custom")) + self.drag_coeff_combo.currentTextChanged.connect(lambda t: self.drag_coeff_value.setEnabled(t == "Custom")) + self.drag_coeff_ll_combo.currentTextChanged.connect(lambda t: self.drag_coeff_ll_value.setEnabled(t == "Custom")) + self.lift_coeff_combo.currentTextChanged.connect(lambda t: self.lift_coeff_value.setEnabled(t == "Custom")) + self.super_area_elev_combo.currentTextChanged.connect(lambda t: self.super_area_elev_value.setEnabled(t == "Custom")) + self.super_area_plain_combo.currentTextChanged.connect(lambda t: self.super_area_plain_value.setEnabled(t == "Custom")) + self.exposed_frontal_area_combo.currentTextChanged.connect(lambda t: self.exposed_frontal_area_value.setEnabled(t == "Custom")) + self.wind_ecc_deck_combo.currentTextChanged.connect(lambda t: self.wind_ecc_deck_value.setEnabled(t == "Custom")) + self.wind_ll_ecc_combo.currentTextChanged.connect(lambda t: self.wind_ll_ecc_value.setEnabled(t == "Custom")) + + return page + + def _build_temperature_load_tab(self): + """Build the Temperature Load tab matching reference design""" + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + page_layout = QVBoxLayout(page) + page_layout.setContentsMargins(12, 12, 12, 12) + page_layout.setSpacing(12) + + content_row = QHBoxLayout() + content_row.setContentsMargins(0, 0, 0, 0) + content_row.setSpacing(16) + + # Left card with inputs + left_card = self._create_card() + left_card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + left_layout = QVBoxLayout(left_card) + left_layout.setContentsMargins(16, 16, 16, 16) + left_layout.setSpacing(12) + + label_style = "font-size: 11px; color: #3a3a3a; background: transparent; border: none;" + field_width = 120 + + # ===== Inputs for evaluation per IRC6 Box ===== + irc6_box = QFrame() + irc6_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + irc6_layout = QVBoxLayout(irc6_box) + irc6_layout.setContentsMargins(12, 12, 12, 12) + irc6_layout.setSpacing(10) + + irc6_title = QLabel("Inputs for evaluation per IRC6") + irc6_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + irc6_layout.addWidget(irc6_title) + + irc6_grid = QGridLayout() + irc6_grid.setContentsMargins(0, 4, 0, 0) + irc6_grid.setHorizontalSpacing(12) + irc6_grid.setVerticalSpacing(10) + irc6_grid.setColumnMinimumWidth(0, 200) + + # Highest Maximum Air Temperature + lbl = QLabel("Highest Maximum Air Temperature:") + lbl.setStyleSheet(label_style) + self.highest_max_temp_input = QLineEdit() + self.highest_max_temp_input.setFixedWidth(field_width) + apply_field_style(self.highest_max_temp_input) + irc6_grid.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + irc6_grid.addWidget(self.highest_max_temp_input, 0, 1, Qt.AlignLeft) + + # Lowest Minimum Air Temperature + lbl = QLabel("Lowest Minimum Air Temperature:") + lbl.setStyleSheet(label_style) + self.lowest_min_temp_input = QLineEdit() + self.lowest_min_temp_input.setFixedWidth(field_width) + apply_field_style(self.lowest_min_temp_input) + irc6_grid.addWidget(lbl, 1, 0, Qt.AlignLeft | Qt.AlignVCenter) + irc6_grid.addWidget(self.lowest_min_temp_input, 1, 1, Qt.AlignLeft) + + irc6_layout.addLayout(irc6_grid) + left_layout.addWidget(irc6_box) + + # ===== Range of Effective Bridge Temperature Box ===== + range_box = QFrame() + range_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + range_layout = QVBoxLayout(range_box) + range_layout.setContentsMargins(12, 12, 12, 12) + range_layout.setSpacing(10) + + range_title = QLabel("Range of Effective Bridge Temperature:") + range_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + range_layout.addWidget(range_title) + + range_grid = QGridLayout() + range_grid.setContentsMargins(0, 4, 0, 0) + range_grid.setHorizontalSpacing(12) + range_grid.setVerticalSpacing(10) + range_grid.setColumnMinimumWidth(0, 200) + + # Minimum + lbl = QLabel("Minimum:") + lbl.setStyleSheet(label_style) + self.bridge_temp_min_input = QLineEdit() + self.bridge_temp_min_input.setFixedWidth(field_width) + apply_field_style(self.bridge_temp_min_input) + range_grid.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + range_grid.addWidget(self.bridge_temp_min_input, 0, 1, Qt.AlignLeft) + + # Maximum + lbl = QLabel("Maximum:") + lbl.setStyleSheet(label_style) + self.bridge_temp_max_input = QLineEdit() + self.bridge_temp_max_input.setFixedWidth(field_width) + apply_field_style(self.bridge_temp_max_input) + range_grid.addWidget(lbl, 1, 0, Qt.AlignLeft | Qt.AlignVCenter) + range_grid.addWidget(self.bridge_temp_max_input, 1, 1, Qt.AlignLeft) + + range_layout.addLayout(range_grid) + left_layout.addWidget(range_box) + + # ===== Coefficient of Thermal Expansion Box ===== + coeff_box = QFrame() + coeff_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 8px; background-color: #ffffff; }") + coeff_layout = QGridLayout(coeff_box) + coeff_layout.setContentsMargins(12, 12, 12, 12) + coeff_layout.setHorizontalSpacing(12) + coeff_layout.setVerticalSpacing(10) + coeff_layout.setColumnMinimumWidth(0, 200) + + lbl = QLabel("Coefficient of Thermal Expansion for Steel:") + lbl.setStyleSheet(label_style) + self.thermal_coeff_combo = QComboBox() + self.thermal_coeff_combo.addItems(["12 × 10⁻⁶ /°C", "11.7 × 10⁻⁶ /°C", "Custom"]) + self.thermal_coeff_combo.setFixedWidth(field_width) + apply_field_style(self.thermal_coeff_combo) + coeff_layout.addWidget(lbl, 0, 0, Qt.AlignLeft | Qt.AlignVCenter) + coeff_layout.addWidget(self.thermal_coeff_combo, 0, 1, Qt.AlignLeft) + + left_layout.addWidget(coeff_box) + left_layout.addStretch() + + # Right description card + right_card = self._create_card() + right_card.setStyleSheet("QFrame { border: 1px solid #9c9c9c; border-radius: 10px; background-color: #d4d4d4; }") + right_card.setMinimumWidth(200) + right_card.setMinimumHeight(400) + right_layout = QVBoxLayout(right_card) + right_layout.setContentsMargins(16, 16, 16, 16) + right_layout.setSpacing(10) + + desc_title = QLabel("Description Box") + desc_title.setAlignment(Qt.AlignCenter) + desc_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + right_layout.addWidget(desc_title) + right_layout.addStretch() + + content_row.addWidget(left_card, 3) + content_row.addWidget(right_card, 2) + + page_layout.addLayout(content_row) + + return page + + def _build_load_combination_tab(self): + """Build the Load Combination tab matching reference design""" + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + page_layout = QVBoxLayout(page) + page_layout.setContentsMargins(12, 12, 12, 12) + page_layout.setSpacing(12) + + content_row = QHBoxLayout() + content_row.setContentsMargins(0, 0, 0, 0) + content_row.setSpacing(16) + + label_style = "font-size: 11px; color: #3a3a3a; background: transparent; border: none;" + + # Left card - combination list + left_card = self._create_card() + left_card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + left_layout = QVBoxLayout(left_card) + left_layout.setContentsMargins(16, 16, 16, 16) + left_layout.setSpacing(12) + + # Auto include checkbox row + auto_row = QHBoxLayout() + auto_row.setContentsMargins(0, 0, 0, 0) + auto_row.setSpacing(8) + auto_label = QLabel("Auto include all IRC 6 Load Combinations") + auto_label.setStyleSheet("font-size: 11px; color: #3a3a3a; background: transparent; border: none;") + self.auto_include_checkbox = QCheckBox() + auto_row.addWidget(auto_label) + auto_row.addWidget(self.auto_include_checkbox) + auto_row.addStretch() + left_layout.addLayout(auto_row) + + # Combination Name label + combo_name_label = QLabel("Combination Name") + combo_name_label.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + left_layout.addWidget(combo_name_label) + + # Combination list area + self.combination_list_widget = QWidget() + self.combination_list_widget.setStyleSheet("background: #ffffff;") + self.combination_list_layout = QVBoxLayout(self.combination_list_widget) + self.combination_list_layout.setContentsMargins(0, 8, 0, 8) + self.combination_list_layout.setSpacing(8) + + # Add sample combinations + sample_combos = ["DL + LL", "1.35 DL + 1.75 LL"] + for combo_text in sample_combos: + combo_label = QLabel(combo_text) + combo_label.setStyleSheet(label_style) + self.combination_list_layout.addWidget(combo_label) + + self.combination_list_layout.addStretch() + left_layout.addWidget(self.combination_list_widget, 1) + + # Middle card - combination editor + middle_card = self._create_card() + middle_card.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 10px; background-color: #ffffff; }") + middle_layout = QVBoxLayout(middle_card) + middle_layout.setContentsMargins(16, 16, 16, 16) + middle_layout.setSpacing(12) + + # Combination Name title + combo_title = QLabel("Combination Name") + combo_title.setStyleSheet("font-size: 12px; font-weight: 700; color: #2b2b2b; background: transparent; border: none;") + middle_layout.addWidget(combo_title) + + # Editor area with table and buttons + editor_row = QHBoxLayout() + editor_row.setContentsMargins(0, 0, 0, 0) + editor_row.setSpacing(12) + + # Table for Load Name and Scale Factor + table_box = QFrame() + table_box.setStyleSheet("QFrame { border: 1px solid #b2b2b2; border-radius: 4px; background-color: #ffffff; }") + table_layout = QVBoxLayout(table_box) + table_layout.setContentsMargins(0, 0, 0, 0) + table_layout.setSpacing(0) + + # Header row + header_widget = QWidget() + header_widget.setStyleSheet("background: #ffffff; border-bottom: 1px solid #b2b2b2;") + header_layout = QHBoxLayout(header_widget) + header_layout.setContentsMargins(8, 8, 8, 8) + header_layout.setSpacing(8) + + load_name_header = QLabel("Load Name") + load_name_header.setStyleSheet("font-size: 11px; font-weight: 600; color: #3a3a3a; background: transparent; border: none;") + load_name_header.setMinimumWidth(80) + scale_factor_header = QLabel("Scale Factor") + scale_factor_header.setStyleSheet("font-size: 11px; font-weight: 600; color: #3a3a3a; background: transparent; border: none;") + scale_factor_header.setMinimumWidth(80) + + header_layout.addWidget(load_name_header) + header_layout.addWidget(scale_factor_header) + table_layout.addWidget(header_widget) + + # Input row + input_widget = QWidget() + input_widget.setStyleSheet("background: #ffffff;") + input_layout = QHBoxLayout(input_widget) + input_layout.setContentsMargins(8, 8, 8, 8) + input_layout.setSpacing(8) + + self.load_name_combo = QComboBox() + self.load_name_combo.addItems(["DL", "LL", "WL", "EL", "TL"]) + self.load_name_combo.setMinimumWidth(80) + apply_field_style(self.load_name_combo) + + self.scale_factor_input = QLineEdit() + self.scale_factor_input.setMinimumWidth(80) + apply_field_style(self.scale_factor_input) + + input_layout.addWidget(self.load_name_combo) + input_layout.addWidget(self.scale_factor_input) + table_layout.addWidget(input_widget) + + # Empty space for more rows + table_layout.addStretch() + + editor_row.addWidget(table_box, 1) + + # Add/Delete buttons column + button_col = QVBoxLayout() + button_col.setContentsMargins(0, 0, 0, 0) + button_col.setSpacing(8) + + self.add_load_btn = QPushButton("Add") + self.add_load_btn.setFixedWidth(60) + self.add_load_btn.setStyleSheet( + "QPushButton { background: #ffffff; border: 1px solid #b2b2b2; border-radius: 4px; padding: 6px 12px; font-size: 11px; color: #3a3a3a; }" + "QPushButton:hover { background: #f0f0f0; }" + "QPushButton:pressed { background: #e0e0e0; }" + ) + + self.delete_load_btn = QPushButton("Delete") + self.delete_load_btn.setFixedWidth(60) + self.delete_load_btn.setStyleSheet( + "QPushButton { background: #ffffff; border: 1px solid #b2b2b2; border-radius: 4px; padding: 6px 12px; font-size: 11px; color: #3a3a3a; }" + "QPushButton:hover { background: #f0f0f0; }" + "QPushButton:pressed { background: #e0e0e0; }" + ) + + button_col.addWidget(self.add_load_btn) + button_col.addWidget(self.delete_load_btn) + button_col.addStretch() + + editor_row.addLayout(button_col) + middle_layout.addLayout(editor_row, 1) + + content_row.addWidget(left_card, 2) + content_row.addWidget(middle_card, 3) + + page_layout.addLayout(content_row) + + return page + + def _create_placeholder_page(self, title): + page = QWidget() + page.setStyleSheet("background-color: #f5f5f5;") + layout = QVBoxLayout(page) + layout.setAlignment(Qt.AlignCenter) + layout.setContentsMargins(20, 20, 20, 20) + + label = QLabel(f"{title} inputs will be added soon.") + label.setAlignment(Qt.AlignCenter) + label.setStyleSheet("font-size: 12px; color: #6a6a6a;") + layout.addWidget(label) + return page diff --git a/src/osdagbridge/desktop/ui/dialogs/project_location.py b/src/osdagbridge/desktop/ui/dialogs/project_location.py new file mode 100644 index 00000000..c263e21f --- /dev/null +++ b/src/osdagbridge/desktop/ui/dialogs/project_location.py @@ -0,0 +1,387 @@ +from PySide6.QtWidgets import ( + QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QWidget, + QCheckBox, QFrame, QPushButton, QComboBox, QSizePolicy, QSizeGrip +) +from PySide6.QtCore import Qt +from osdagbridge.desktop.ui.utils.custom_titlebar import CustomTitleBar + +class NoScrollComboBox(QComboBox): + def wheelEvent(self, event): + event.ignore() # Prevent changing selection on scroll + +def apply_field_style(widget): + widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + widget.setMinimumHeight(28) + + if isinstance(widget, QComboBox): + style = """ + QComboBox{ + padding: 1px 7px; + border: 1px solid black; + border-radius: 5px; + background-color: white; + color: black; + } + QComboBox::drop-down{ + subcontrol-origin: padding; + subcontrol-position: top right; + border-left: 0px; + } + QComboBox::down-arrow{ + image: url(:/vectors/arrow_down_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox::down-arrow:on { + image: url(:/vectors/arrow_up_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox QAbstractItemView{ + background-color: white; + border: 1px solid black; + outline: none; + } + QComboBox QAbstractItemView::item{ + color: black; + background-color: white; + border: none; + border: 1px solid white; + border-radius: 0; + padding: 2px; + } + QComboBox QAbstractItemView::item:hover{ + border: 1px solid #90AF13; + background-color: #90AF13; + color: black; + } + QComboBox QAbstractItemView::item:selected{ + background-color: #90AF13; + color: black; + border: 1px solid #90AF13; + } + QComboBox QAbstractItemView::item:selected:hover{ + background-color: #90AF13; + color: black; + border: 1px solid #94b816; + } + """ + widget.setStyleSheet(style) + elif isinstance(widget, QLineEdit): + widget.setStyleSheet(""" + QLineEdit { + padding: 1px 7px; + border: 1px solid #070707; + border-radius: 6px; + background-color: white; + color: #000000; + font-weight: normal; + } + """) + + +class ProjectLocationDialog(QDialog): + """Dialog for selecting project location with multiple input methods""" + + STATE_DISTRICTS = { + "Select State": ["Select District"], + "Delhi": ["Central Delhi", "East Delhi", "New Delhi", "North Delhi", "North East Delhi", + "North West Delhi", "South Delhi", "South East Delhi", "South West Delhi", "West Delhi"], + "Maharashtra": ["Mumbai", "Pune", "Nagpur", "Thane", "Nashik", "Aurangabad", "Solapur", + "Amravati", "Kolhapur", "Raigad", "Satara", "Sangli"], + "Karnataka": ["Bangalore", "Mysore", "Hubli", "Belgaum", "Mangalore", "Gulbarga", + "Bellary", "Bijapur", "Shimoga", "Tumkur", "Davangere"], + "Tamil Nadu": ["Chennai", "Coimbatore", "Madurai", "Tiruchirappalli", "Salem", "Tirunelveli", + "Tiruppur", "Erode", "Vellore", "Thoothukudi", "Dindigul"], + "West Bengal": ["Kolkata", "Howrah", "Darjeeling", "Siliguri", "Asansol", "Durgapur", + "Bardhaman", "Malda", "Jalpaiguri", "Murshidabad", "Nadia"] + } + + def __init__(self, parent=None): + super().__init__(parent) + self.setMinimumWidth(850) + self.setMinimumHeight(650) + self.setObjectName("project_location_dialog") + self.setStyleSheet(""" + QDialog#project_location_dialog { + background-color: #FFFFFF; + border: 1px solid #90AF13; + } + """) + + self._setup_ui() + self._connect_signals() + + def setupWrapper(self): + self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowSystemMenuHint) + + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(1, 1, 1, 1) + main_layout.setSpacing(0) + + self.title_bar = CustomTitleBar() + self.title_bar.setTitle("Project Location") + main_layout.addWidget(self.title_bar) + + self.content_widget = QWidget(self) + main_layout.addWidget(self.content_widget, 1) + + size_grip = QSizeGrip(self) + size_grip.setFixedSize(16, 16) + + overlay = QHBoxLayout() + overlay.setContentsMargins(0, 0, 4, 4) + overlay.addStretch(1) + overlay.addWidget(size_grip, 0, Qt.AlignBottom | Qt.AlignRight) + main_layout.addLayout(overlay) + + def _setup_ui(self): + """Setup the user interface""" + self.setupWrapper() + main_layout = QVBoxLayout(self.content_widget) + main_layout.setContentsMargins(20, 20, 20, 20) + main_layout.setSpacing(15) + + # Add sections + self._add_coordinates_section(main_layout) + self._add_separator(main_layout) + self._add_location_name_section(main_layout) + self._add_separator(main_layout) + self._add_map_section(main_layout) + self._add_separator(main_layout) + self._add_irc_values_section(main_layout) + self._add_separator(main_layout) + self._add_custom_params_section(main_layout) + + main_layout.addStretch() + + self._add_buttons(main_layout) + + def _add_coordinates_section(self, layout): + """Add the coordinates input section""" + coords_row = QHBoxLayout() + coords_row.setSpacing(15) + + self.coords_checkbox = QCheckBox("Enter Coordinates") + coords_row.addWidget(self.coords_checkbox) + coords_row.addStretch() + + lat_label = QLabel("Latitude (°)") + lat_label.setStyleSheet("font-size: 11px;") + coords_row.addWidget(lat_label) + + self.latitude_input = QLineEdit() + self.latitude_input.setMaximumWidth(120) + self.latitude_input.setEnabled(False) + apply_field_style(self.latitude_input) + coords_row.addWidget(self.latitude_input) + + lng_label = QLabel("Longitude (°)") + lng_label.setStyleSheet("font-size: 11px;") + coords_row.addWidget(lng_label) + + self.longitude_input = QLineEdit() + self.longitude_input.setMaximumWidth(120) + self.longitude_input.setEnabled(False) + apply_field_style(self.longitude_input) + coords_row.addWidget(self.longitude_input) + + layout.addLayout(coords_row) + + def _add_location_name_section(self, layout): + """Add the location name input section""" + location_row = QHBoxLayout() + location_row.setSpacing(15) + + self.location_checkbox = QCheckBox("Enter Location Name") + location_row.addWidget(self.location_checkbox) + location_row.addStretch() + + state_label = QLabel("State") + state_label.setStyleSheet("font-size: 11px;") + location_row.addWidget(state_label) + + self.state_combo = NoScrollComboBox() + self.state_combo.setMaximumWidth(150) + self.state_combo.setEnabled(False) + self.state_combo.addItems(list(self.STATE_DISTRICTS.keys())) + apply_field_style(self.state_combo) + location_row.addWidget(self.state_combo) + + district_label = QLabel("District") + district_label.setStyleSheet("font-size: 11px;") + location_row.addWidget(district_label) + + self.district_combo = NoScrollComboBox() + self.district_combo.setMaximumWidth(150) + self.district_combo.setEnabled(False) + self.district_combo.addItems(["Select District"]) + apply_field_style(self.district_combo) + location_row.addWidget(self.district_combo) + + layout.addLayout(location_row) + + def _add_map_section(self, layout): + """Add the map selection section""" + map_section = QVBoxLayout() + map_section.setSpacing(8) + + self.map_checkbox = QCheckBox("Select on Map") + map_section.addWidget(self.map_checkbox) + + # Map placeholder + self.map_placeholder = QLabel() + self.map_placeholder.setAlignment(Qt.AlignCenter) + self.map_placeholder.setMinimumHeight(200) + self.map_placeholder.setText("Map Placeholder\n(Will be added later)") + self.map_placeholder.setEnabled(False) + map_section.addWidget(self.map_placeholder) + + layout.addLayout(map_section) + + def _add_irc_values_section(self, layout): + """Add the IRC 6 (2017) values section""" + results_section = QVBoxLayout() + results_section.setSpacing(8) + + results_title = QLabel("IRC 6 (2017) Values") + results_section.addWidget(results_title) + + self.wind_speed_label = QLabel("Basic Wind Speed (m/sec)") + results_section.addWidget(self.wind_speed_label) + + self.seismic_zone_label = QLabel("Seismic Zone and Zone Factor") + results_section.addWidget(self.seismic_zone_label) + + self.temp_label = QLabel("Shade Air Temperature (°C)") + results_section.addWidget(self.temp_label) + + layout.addLayout(results_section) + + def _add_custom_params_section(self, layout): + """Add the custom loading parameters checkbox""" + self.custom_params_checkbox = QCheckBox("Tabulate Custom Loading Parameters") + layout.addWidget(self.custom_params_checkbox) + + def _add_separator(self, layout): + """Add a horizontal separator line""" + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + line.setStyleSheet("background-color: #d0d0d0;") + layout.addWidget(line) + + def _add_buttons(self, layout): + """Add OK and Cancel buttons""" + btn_layout = QHBoxLayout() + btn_layout.addStretch() + + ok_btn = QPushButton("OK") + ok_btn.setCursor(Qt.CursorShape.PointingHandCursor) + ok_btn.setMinimumWidth(100) + ok_btn.clicked.connect(self.accept) + btn_layout.addWidget(ok_btn) + + cancel_btn = QPushButton("Cancel") + cancel_btn.setCursor(Qt.CursorShape.PointingHandCursor) + cancel_btn.setMinimumWidth(100) + cancel_btn.clicked.connect(self.reject) + btn_layout.addWidget(cancel_btn) + + layout.addLayout(btn_layout) + + def _connect_signals(self): + """Connect all signal handlers""" + # Enable/disable coordinates inputs + self.coords_checkbox.stateChanged.connect( + lambda state: self._toggle_coordinates_inputs(state == 2) + ) + + # Enable/disable location inputs + self.location_checkbox.stateChanged.connect( + lambda state: self._toggle_location_inputs(state == 2) + ) + + # Handle map checkbox + self.map_checkbox.stateChanged.connect(self._on_map_checkbox_changed) + + # Update districts when state changes + self.state_combo.currentTextChanged.connect(self._on_state_changed) + + def _toggle_coordinates_inputs(self, enabled): + """Enable or disable coordinate input fields""" + self.latitude_input.setEnabled(enabled) + self.longitude_input.setEnabled(enabled) + + def _toggle_location_inputs(self, enabled): + """Enable or disable location input fields""" + self.state_combo.setEnabled(enabled) + self.district_combo.setEnabled(enabled) + + def _on_state_changed(self, state_name): + """Update districts based on selected state""" + districts = self.STATE_DISTRICTS.get(state_name, ["Select District"]) + self.district_combo.clear() + self.district_combo.addItems(districts) + + def _on_map_checkbox_changed(self, state): + """Handle map checkbox state changes""" + enabled = (state == 2) + self.map_placeholder.setEnabled(enabled) + + if enabled: + self.map_placeholder.setStyleSheet(""" + QLabel { + border: 2px solid #90AF13; + background-color: white; + padding: 20px; + color: #666666; + } + """) + self.map_placeholder.setText( + "Map Placeholder\n(Click to select location)\n(Will be implemented later)" + ) + else: + self.map_placeholder.setStyleSheet(""" + QLabel { + border: 1px solid #e0e0e0; + background-color: #f5f5f5; + padding: 20px; + color: #999999; + } + """) + self.map_placeholder.setText("Map Placeholder\n(Will be added later)") + + def get_selected_location(self): + """ + Get the selected location data + + Returns: + dict: Dictionary containing location information based on selection method + """ + result = { + 'method': None, + 'data': {} + } + + if self.coords_checkbox.isChecked(): + result['method'] = 'coordinates' + result['data'] = { + 'latitude': self.latitude_input.text(), + 'longitude': self.longitude_input.text() + } + elif self.location_checkbox.isChecked(): + result['method'] = 'location_name' + result['data'] = { + 'state': self.state_combo.currentText(), + 'district': self.district_combo.currentText() + } + elif self.map_checkbox.isChecked(): + result['method'] = 'map' + result['data'] = {} # Will be populated when map is implemented + + result['custom_params'] = self.custom_params_checkbox.isChecked() + + return result \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/docks/input_dock.py b/src/osdagbridge/desktop/ui/docks/input_dock.py new file mode 100644 index 00000000..cb5d9b2a --- /dev/null +++ b/src/osdagbridge/desktop/ui/docks/input_dock.py @@ -0,0 +1,1640 @@ +import sys +import os +import math +from PySide6.QtWidgets import ( + QApplication, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, + QComboBox, QScrollArea, QLabel, QFormLayout, QLineEdit, QGroupBox, QSizePolicy, QMessageBox, QInputDialog, QDialog, QCheckBox, QFrame, + QDialogButtonBox, QStackedWidget +) +from PySide6.QtCore import Qt, QRegularExpression, QSize, QTimer, QPoint, QEvent +from PySide6.QtGui import QPixmap, QDoubleValidator, QRegularExpressionValidator, QIcon +from PySide6.QtSvgWidgets import * +from osdagbridge.core.utils.common import * +from osdagbridge.desktop.ui.dialogs.additional_inputs import AdditionalInputs +from osdagbridge.desktop.ui.utils.custom_buttons import DockCustomButton +from osdagbridge.desktop.ui.dialogs.project_location import ProjectLocationDialog + + +STEEL_MEMBER_FIELDS = [ + "Ultimate Tensile Strength, Fu (MPa)", + "Yield Strength, Fy (MPa)", + "Modulus of Elasticity, E (GPa)", + "Modulus of Rigidity, G (GPa)", + "Poisson's Ratio, ν", + "Thermal Expansion Coefficient, (×10⁻⁶/°C)", +] + +DECK_MEMBER_FIELDS = [ + "Characteristic Compressive (Cube) Strength of Concrete, (fck)cu (MPa)", + "Mean Tensile Strength of Concrete, fctm (MPa)", + "Secant Modulus of Elasticity of Concrete, Ecm (GPa)", + "Ecm Multiplication Factor", +] + +STEEL_MODULUS_E_GPA = 200.0 +STEEL_MODULUS_G_GPA = 77.0 +STEEL_POISSON_RATIO = 0.30 +STEEL_THERMAL_COEFF = 11.7 + +STEEL_GRADE_BASE_VALUES = { + 250: {"Fy": 250, "Fu": 410}, + 275: {"Fy": 275, "Fu": 430}, + 300: {"Fy": 300, "Fu": 440}, + 350: {"Fy": 350, "Fu": 490}, + 410: {"Fy": 410, "Fu": 540}, + 450: {"Fy": 450, "Fu": 570}, + 550: {"Fy": 550, "Fu": 650}, + 600: {"Fy": 600, "Fu": 700}, + 650: {"Fy": 650, "Fu": 750}, +} + +ECM_FACTOR_OPTIONS = [ + ("Quartzite/granite aggregates = 1", 1.0), + ("Limestone aggregates = 0.9", 0.9), + ("Sandstone aggregates = 0.7", 0.7), + ("Basalt aggregates = 1.2", 1.2), + ("Custom", None), +] +ECM_FACTOR_LABELS = [text for text, _ in ECM_FACTOR_OPTIONS] +DEFAULT_ECM_FACTOR_LABEL = ECM_FACTOR_OPTIONS[0][0] +CUSTOM_ECM_FACTOR_LABEL = "Custom" + + +class NoScrollComboBox(QComboBox): + def wheelEvent(self, event): + event.ignore() # Prevent changing selection on scroll + +def apply_field_style(widget): + widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + widget.setMinimumHeight(28) + + if isinstance(widget, QComboBox): + style = """ + QComboBox{ + padding: 1px 7px; + border: 1px solid black; + border-radius: 5px; + background-color: white; + color: black; + } + QComboBox::drop-down{ + subcontrol-origin: padding; + subcontrol-position: top right; + border-left: 0px; + } + QComboBox::down-arrow{ + image: url(:/vectors/arrow_down_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox::down-arrow:on { + image: url(:/vectors/arrow_up_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox QAbstractItemView{ + background-color: white; + border: 1px solid black; + outline: none; + } + QComboBox QAbstractItemView::item{ + color: black; + background-color: white; + border: none; + border: 1px solid white; + border-radius: 0; + padding: 2px; + } + QComboBox QAbstractItemView::item:hover{ + border: 1px solid #90AF13; + background-color: #90AF13; + color: black; + } + QComboBox QAbstractItemView::item:selected{ + background-color: #90AF13; + color: black; + border: 1px solid #90AF13; + } + QComboBox QAbstractItemView::item:selected:hover{ + background-color: #90AF13; + color: black; + border: 1px solid #94b816; + } + QComboBox:disabled{ + background: #f1f1f1; + color: #666; + } + """ + widget.setStyleSheet(style) + elif isinstance(widget, QLineEdit): + widget.setStyleSheet(""" + QLineEdit { + padding: 1px 7px; + border: 1px solid #070707; + border-radius: 6px; + background-color: white; + color: #000000; + font-weight: normal; + } + QLineEdit:disabled{ + background: #f1f1f1; + color: #666; + } + """) + + +class MaterialPropertiesDialog(QDialog): + MEMBER_OPTIONS = ["Girder", "Cross Bracing", "End Diaphragm", "Deck"] + STEEL_MEMBERS = {"Girder", "Cross Bracing", "End Diaphragm"} + + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle("Material Properties") + self.setMinimumWidth(580) + self.setStyleSheet("background-color: white;") + + self.parent_dock = parent + self._loading = False + self.current_member = None + self.member_data = {} + + self.member_combo = NoScrollComboBox() + self.member_combo.addItems(self.MEMBER_OPTIONS) + apply_field_style(self.member_combo) + + self.material_combo = NoScrollComboBox() + apply_field_style(self.material_combo) + + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(20, 16, 20, 16) + + # Create a container widget for all form fields + form_container = QWidget() + form_layout = QVBoxLayout(form_container) + form_layout.setContentsMargins(0, 0, 0, 0) + form_layout.setSpacing(10) + + # Member row + member_row = QHBoxLayout() + member_row.setContentsMargins(0, 0, 0, 0) + member_row.setSpacing(18) + member_label = QLabel("Member*:") + member_label.setStyleSheet("font-size: 12px; color: #2d2d2d;") + member_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + member_label.setFixedWidth(280) + self.member_combo.setFixedWidth(242) + member_row.addWidget(member_label) + member_row.addWidget(self.member_combo) + member_row.addStretch() + form_layout.addLayout(member_row) + + # Material row + material_row = QHBoxLayout() + material_row.setContentsMargins(0, 0, 0, 0) + material_row.setSpacing(18) + material_label = QLabel("Material*:") + material_label.setStyleSheet("font-size: 12px; color: #2d2d2d;") + material_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + material_label.setFixedWidth(280) + self.material_combo.setFixedWidth(242) + material_row.addWidget(material_label) + material_row.addWidget(self.material_combo) + material_row.addStretch() + form_layout.addLayout(material_row) + + main_layout.addWidget(form_container) + + self.stack = QStackedWidget() + self.stack.setContentsMargins(0, 0, 0, 0) + self.steel_page = self._build_steel_form() + self.deck_page = self._build_deck_form() + self.stack.addWidget(self.steel_page) + self.stack.addWidget(self.deck_page) + main_layout.addWidget(self.stack) + + # Updated default row with proper alignment + default_row = QHBoxLayout() + default_row.setContentsMargins(0, 0, 0, 0) + default_row.setSpacing(18) + default_label = QLabel("Default") + default_label.setStyleSheet("font-size: 12px; color: #2d2d2d;") + default_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + default_label.setFixedWidth(280) + self.default_checkbox = QCheckBox() + # Create container for checkbox to align it to the left + checkbox_container = QWidget() + checkbox_layout = QHBoxLayout(checkbox_container) + checkbox_layout.setContentsMargins(0, 0, 0, 0) + checkbox_layout.setSpacing(0) + checkbox_layout.addWidget(self.default_checkbox) + checkbox_layout.addStretch() + + default_row.addWidget(default_label) + default_row.addWidget(checkbox_container) + main_layout.addLayout(default_row) + + self.member_combo.currentTextChanged.connect(self._on_member_changed) + self.material_combo.currentTextChanged.connect(self._on_material_changed) + self.default_checkbox.stateChanged.connect(self._on_default_toggled) + + self._initialize_member_data() + self._on_member_changed(self.member_combo.currentText()) + + def closeEvent(self, event): + self._save_current_member_form() + super().closeEvent(event) + + def _build_steel_form(self): + widget = QWidget() + layout = QVBoxLayout(widget) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(10) + self.steel_field_inputs = {} + for label_text in STEEL_MEMBER_FIELDS: + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(18) + label = QLabel(label_text) + label.setStyleSheet("font-size: 12px; color: #2d2d2d;") + label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + label.setFixedWidth(280) + line_edit = QLineEdit() + line_edit.setFixedWidth(242) + apply_field_style(line_edit) + # Add validator for 1 decimal place + line_edit.setValidator(QDoubleValidator(0.0, 99999.0, 1)) + line_edit.textEdited.connect(self._handle_user_override) + self.steel_field_inputs[label_text] = line_edit + row.addWidget(label) + row.addWidget(line_edit) + row.addStretch() + layout.addLayout(row) + layout.addStretch() + return widget + + def _build_deck_form(self): + widget = QWidget() + layout = QVBoxLayout(widget) + layout.setSpacing(10) + self.deck_field_inputs = {} + for label_text in DECK_MEMBER_FIELDS: + row = QHBoxLayout() + row.setSpacing(18) + label = QLabel(label_text) + label.setStyleSheet("font-size: 12px; color: #2d2d2d;") + label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + label.setFixedWidth(280) + if label_text == "Ecm Multiplication Factor": + self.deck_factor_combo = NoScrollComboBox() + self.deck_factor_combo.addItems(ECM_FACTOR_LABELS) + self.deck_factor_combo.setFixedWidth(242) + apply_field_style(self.deck_factor_combo) + self.deck_factor_combo.currentTextChanged.connect(self._on_factor_changed) + + self.deck_factor_custom_input = QLineEdit() + apply_field_style(self.deck_factor_custom_input) + self.deck_factor_custom_input.setPlaceholderText("Custom factor") + self.deck_factor_custom_input.setFixedWidth(242) + self.deck_factor_custom_input.setVisible(False) + self.deck_factor_custom_input.setEnabled(False) + self.deck_factor_custom_input.setValidator(QDoubleValidator(0.1, 5.0, 1)) + self.deck_factor_custom_input.textEdited.connect(self._handle_user_override) + + row.addWidget(label) + row.addWidget(self.deck_factor_combo) + row.addStretch() + + # Add custom input row (hidden by default) + custom_row = QHBoxLayout() + custom_row.setContentsMargins(0, 0, 0, 0) + custom_row.setSpacing(18) + custom_label = QLabel("") # Empty label for alignment + custom_label.setFixedWidth(280) + custom_row.addWidget(custom_label) + custom_row.addWidget(self.deck_factor_custom_input) + custom_row.addStretch() + layout.addLayout(custom_row) + + self.deck_field_inputs[label_text] = self.deck_factor_combo + else: + line_edit = QLineEdit() + line_edit.setFixedWidth(242) + apply_field_style(line_edit) + # Add validator for 1 decimal place + line_edit.setValidator(QDoubleValidator(0.0, 99999.0, 1)) + line_edit.textEdited.connect(self._handle_user_override) + row.addWidget(label) + row.addWidget(line_edit) + row.addStretch() + self.deck_field_inputs[label_text] = line_edit + layout.addLayout(row) + layout.addStretch() + return widget + + def _initialize_member_data(self): + for member in self.MEMBER_OPTIONS: + material = self._get_parent_grade(member) + fields = self._default_fields_for_member(member, material) + self.member_data[member] = { + "material": material, + "fields": fields, + "is_default": True, + "factor_label": DEFAULT_ECM_FACTOR_LABEL if member == "Deck" else None, + "custom_factor": "1.0" if member == "Deck" else None, + } + + def _default_fields_for_member(self, member, material=None, factor_label=None, custom_factor=None): + if member == "Deck": + grade = material or self._get_parent_grade(member) or (VALUES_DECK_CONCRETE_GRADE[0] if VALUES_DECK_CONCRETE_GRADE else "") + factor_label = factor_label or DEFAULT_ECM_FACTOR_LABEL + factor_value = self._factor_value_from_label(factor_label, custom_factor) + return self._deck_defaults(grade, factor_value) + grade = material or self._get_parent_grade(member) or (VALUES_MATERIAL[0] if VALUES_MATERIAL else "") + return self._steel_defaults(grade) + + def _steel_defaults(self, grade): + grade_value = self._extract_numeric_grade(grade) + defaults = STEEL_GRADE_BASE_VALUES.get(grade_value, STEEL_GRADE_BASE_VALUES[250]) + return { + "Ultimate Tensile Strength, Fu (MPa)": "{:.1f}".format(defaults["Fu"]), + "Yield Strength, Fy (MPa)": "{:.1f}".format(defaults["Fy"]), + "Modulus of Elasticity, E (GPa)": "{:.1f}".format(STEEL_MODULUS_E_GPA), + "Modulus of Rigidity, G (GPa)": "{:.1f}".format(STEEL_MODULUS_G_GPA), + "Poisson's Ratio, ν": "{:.1f}".format(STEEL_POISSON_RATIO), + "Thermal Expansion Coefficient, (×10⁻⁶/°C)": "{:.1f}".format(STEEL_THERMAL_COEFF), + } + + def _deck_defaults(self, grade, factor_value): + strength = self._extract_numeric_grade(grade, default=25) + fck = float(strength) + fctm = round(0.7 * math.sqrt(fck), 1) + ecm = round(5.0 * math.sqrt(fck) * factor_value, 1) + return { + "Characteristic Compressive (Cube) Strength of Concrete, (fck)cu (MPa)": "{:.1f}".format(fck), + "Mean Tensile Strength of Concrete, fctm (MPa)": "{:.1f}".format(fctm), + "Secant Modulus of Elasticity of Concrete, Ecm (GPa)": "{:.1f}".format(ecm), + "Ecm Multiplication Factor": "{:.1f}".format(factor_value), + } + + def _extract_numeric_grade(self, grade, default=250): + digits = ''.join(ch for ch in grade if ch.isdigit()) + try: + return int(digits) if digits else default + except ValueError: + return default + + def _materials_for_member(self, member): + return VALUES_DECK_CONCRETE_GRADE if member == "Deck" else VALUES_MATERIAL + + def _on_member_changed(self, member): + if self.current_member: + self._save_current_member_form() + + self.current_member = member + is_deck = member == "Deck" + self.stack.setCurrentWidget(self.deck_page if is_deck else self.steel_page) + + data = self.member_data.get(member) + if not data: + self.member_data[member] = self._create_default_entry(member) + data = self.member_data[member] + + if data.get("is_default"): + self._apply_defaults_for_member(member, update_ui=False) + + materials = self._materials_for_member(member) + self._loading = True + self.material_combo.clear() + self.material_combo.addItems(materials) + if data["material"] in materials: + self.material_combo.setCurrentText(data["material"]) + elif materials: + self.material_combo.setCurrentIndex(0) + data["material"] = self.material_combo.currentText() + + self.default_checkbox.setChecked(data.get("is_default", False)) + if is_deck: + self._populate_deck_fields(data) + else: + self._populate_steel_fields(data) + self._loading = False + + def _populate_steel_fields(self, data): + for label, widget in self.steel_field_inputs.items(): + value = data["fields"].get(label, "") + # Format to 1 decimal place + try: + formatted_value = "{:.1f}".format(float(value)) + widget.setText(formatted_value) + except (ValueError, TypeError): + widget.setText(value) + + def _populate_deck_fields(self, data): + for label, widget in self.deck_field_inputs.items(): + if label == "Ecm Multiplication Factor": + factor_label = data.get("factor_label", DEFAULT_ECM_FACTOR_LABEL) + if factor_label not in ECM_FACTOR_LABELS: + factor_label = DEFAULT_ECM_FACTOR_LABEL + self.deck_factor_combo.blockSignals(True) + self.deck_factor_combo.setCurrentText(factor_label) + self.deck_factor_combo.blockSignals(False) + self._update_custom_factor_visibility(factor_label) + self.deck_factor_custom_input.blockSignals(True) + custom_val = data.get("custom_factor", "1.0") + try: + formatted_custom = "{:.1f}".format(float(custom_val)) + self.deck_factor_custom_input.setText(formatted_custom) + except (ValueError, TypeError): + self.deck_factor_custom_input.setText(custom_val) + self.deck_factor_custom_input.blockSignals(False) + else: + value = data["fields"].get(label, "") + # Format to 1 decimal place + try: + formatted_value = "{:.1f}".format(float(value)) + widget.setText(formatted_value) + except (ValueError, TypeError): + widget.setText(value) + + def _save_current_member_form(self): + if not self.current_member: + return + data = self.member_data.setdefault(self.current_member, self._create_default_entry(self.current_member)) + data["material"] = self.material_combo.currentText() + if self.current_member == "Deck": + for label, widget in self.deck_field_inputs.items(): + if label == "Ecm Multiplication Factor": + data["factor_label"] = self.deck_factor_combo.currentText() + data["custom_factor"] = self.deck_factor_custom_input.text() or "1.0" + else: + data["fields"][label] = widget.text() + factor_value = self._factor_value_from_label(data["factor_label"], data.get("custom_factor")) + data["fields"]["Ecm Multiplication Factor"] = "{:.1f}".format(factor_value) + else: + for label, widget in self.steel_field_inputs.items(): + data["fields"][label] = widget.text() + data["is_default"] = self.default_checkbox.isChecked() + + def _create_default_entry(self, member): + material = self._get_parent_grade(member) + return { + "material": material, + "fields": self._default_fields_for_member(member, material), + "is_default": True, + "factor_label": DEFAULT_ECM_FACTOR_LABEL if member == "Deck" else None, + "custom_factor": "1.0" if member == "Deck" else None, + } + + def _apply_defaults_for_member(self, member, update_ui=True): + data = self.member_data.setdefault(member, self._create_default_entry(member)) + grade = self._get_parent_grade(member) or data.get("material") + materials = self._materials_for_member(member) + if grade not in materials and materials: + grade = materials[0] + data["material"] = grade + if member == "Deck": + data["factor_label"] = DEFAULT_ECM_FACTOR_LABEL + data["custom_factor"] = "1.0" + factor_value = self._factor_value_from_label(DEFAULT_ECM_FACTOR_LABEL) + data["fields"] = self._deck_defaults(grade, factor_value) + else: + data["fields"] = self._steel_defaults(grade) + data["is_default"] = True + + if update_ui and member == self.current_member: + self._loading = True + self.material_combo.setCurrentText(grade) + if member == "Deck": + self._populate_deck_fields(data) + else: + self._populate_steel_fields(data) + self.default_checkbox.setChecked(True) + self._loading = False + + def _factor_value_from_label(self, label, custom_factor=None): + for text, value in ECM_FACTOR_OPTIONS: + if text == label: + if value is None: + try: + return float(custom_factor) if custom_factor else 1.0 + except ValueError: + return 1.0 + return value + return 1.0 + + def _reset_current_member_to_defaults(self): + if not self.current_member: + return + + self._apply_defaults_for_member(self.current_member, update_ui=False) + data = self.member_data.get(self.current_member) + if not data: + return + + target_material = data.get("material", "") + self._loading = True + if target_material: + index = self.material_combo.findText(target_material) + if index >= 0: + self.material_combo.setCurrentIndex(index) + elif self.material_combo.count() > 0: + self.material_combo.setCurrentIndex(0) + data["material"] = self.material_combo.currentText() + if self.current_member == "Deck": + self._populate_deck_fields(data) + else: + self._populate_steel_fields(data) + self._loading = False + + self.default_checkbox.blockSignals(True) + self.default_checkbox.setChecked(True) + self.default_checkbox.blockSignals(False) + self._save_current_member_form() + + def _update_custom_factor_visibility(self, label): + is_custom = label == CUSTOM_ECM_FACTOR_LABEL + self.deck_factor_custom_input.setVisible(is_custom) + self.deck_factor_custom_input.setEnabled(is_custom) + self.deck_factor_combo.setVisible(not is_custom) + + def _on_material_changed(self, material): + if self._loading: + return + data = self.member_data.get(self.current_member) + if data: + data["material"] = material + self._handle_user_override() + + def _on_default_toggled(self, state): + if self._loading: + return + try: + check_state = Qt.CheckState(state) + except ValueError: + check_state = Qt.CheckState.Checked if bool(state) else Qt.CheckState.Unchecked + if check_state == Qt.CheckState.Checked: + self._reset_current_member_to_defaults() + else: + data = self.member_data.get(self.current_member) + if data: + data["is_default"] = False + + def _on_factor_changed(self, label): + self._update_custom_factor_visibility(label) + self._handle_user_override() + + def _handle_user_override(self): + if self._loading: + return + if self.default_checkbox.isChecked(): + self._loading = True + self.default_checkbox.setChecked(False) + self._loading = False + data = self.member_data.get(self.current_member) + if data: + data["is_default"] = False + self._save_current_member_form() + + def _get_parent_grade(self, member): + parent = self.parent_dock + if not parent: + return "" + mapping = { + "Girder": getattr(parent, "girder_combo", None), + "Cross Bracing": getattr(parent, "cross_bracing_combo", None), + "End Diaphragm": getattr(parent, "end_diaphragm_combo", None), + "Deck": getattr(parent, "deck_combo", None), + } + combo = mapping.get(member) + return combo.currentText() if combo else "" + + def set_member(self, member): + index = self.member_combo.findText(member) + if index >= 0: + self.member_combo.setCurrentIndex(index) + + def sync_with_parent_defaults(self): + for member, data in self.member_data.items(): + if data.get("is_default"): + self._apply_defaults_for_member(member, update_ui=(member == self.current_member)) + + +class InputDock(QWidget): + def __init__(self, backend, parent): + super().__init__() + self.parent = parent + self.backend = backend + self.input_widget = None + self.structure_type_combo = None + self.project_location_combo = None + self.custom_location_input = None + self.include_median_combo = None + self.footpath_combo = None + self.additional_inputs = None + self.additional_inputs_widget = None + self.material_dialog = None + self.additional_inputs_btn = None + self.lock_btn = None + self.scroll_area = None + self.is_locked = False + + self.setStyleSheet("background: transparent;") + self.main_layout = QHBoxLayout(self) + self.main_layout.setContentsMargins(0, 0, 0, 0) + self.main_layout.setSpacing(0) + + self.left_container = QWidget() + + # Get input fields from backend + input_field_list = self.backend.input_values() + + self.build_left_panel(input_field_list) + self.main_layout.addWidget(self.left_container) + + # Toggle strip + self.toggle_strip = QWidget() + self.toggle_strip.setStyleSheet("background-color: #90AF13;") + self.toggle_strip.setFixedWidth(6) + toggle_layout = QVBoxLayout(self.toggle_strip) + toggle_layout.setContentsMargins(0, 0, 0, 0) + toggle_layout.setSpacing(0) + toggle_layout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) + + self.toggle_btn = QPushButton("❮") + self.toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.toggle_btn.setFixedSize(6, 60) + self.toggle_btn.setToolTip("Hide panel") + self.toggle_btn.clicked.connect(self.toggle_input_dock) + self.toggle_btn.setStyleSheet(""" + QPushButton { + background-color: #6c8408; + color: white; + font-size: 12px; + font-weight: bold; + padding: 0px; + border: none; + } + QPushButton:hover { + background-color: #5e7407; + } + """) + toggle_layout.addStretch() + toggle_layout.addWidget(self.toggle_btn) + toggle_layout.addStretch() + self.main_layout.addWidget(self.toggle_strip) + + def get_validator(self, validator): + if validator == 'Int Validator': + return QRegularExpressionValidator(QRegularExpression("^(0|[1-9]\\d*)(\\.\\d+)?$")) + elif validator == 'Double Validator': + return QDoubleValidator() + else: + return None + + def on_structure_type_changed(self, text): + """Handle structure type combo box changes""" + if text == "Other": + if hasattr(self, 'structure_note'): + self.structure_note.setVisible(True) + else: + if hasattr(self, 'structure_note'): + self.structure_note.setVisible(False) + + def show_project_location_dialog(self): + """Show Project Location selection dialog""" + dialog = ProjectLocationDialog() + + if dialog.exec() == QDialog.Accepted: + location_data = dialog.get_selected_location() + + # Process the location data as needed + if location_data['method'] == 'coordinates': + lat = location_data['data']['latitude'] + lon = location_data['data']['longitude'] + print(f"Selected coordinates: {lat}, {lon}") + + elif location_data['method'] == 'location_name': + state = location_data['data']['state'] + district = location_data['data']['district'] + print(f"Selected location: {district}, {state}") + + elif location_data['method'] == 'map': + print("Map selection (to be implemented)") + + if location_data['custom_params']: + print("Custom loading parameters requested") + + # Lock-Tooltip-Events-Starts------------------------------------------------------------------------- + def eventFilter(self, obj, event): + # Check if it's the scroll area and it's a mouse press + if obj == self.scroll_area and event.type() == QEvent.MouseButtonPress: + if self.is_locked: + self.show_lock_tooltip() + return True # Block the event + return super().eventFilter(obj, event) + + def clear_force_hover(self): + if self.lock_btn: + self.lock_btn.setProperty("forceHover", False) + self.lock_btn.style().polish(self.lock_btn) + self.lock_btn.update() + + def show_lock_tooltip(self): + # Stop any existing timer first + if hasattr(self, 'tooltip_timer') and self.tooltip_timer.isActive(): + self.tooltip_timer.stop() + + # Position tooltip to the right of the lock button + lock_global_pos = self.lock_btn.mapToGlobal(self.lock_btn.rect().topRight()) + tooltip_pos = lock_global_pos + QPoint(5, 0) + self.lock_btn.setProperty("forceHover", True) + self.lock_btn.style().polish(self.lock_btn) + self.lock_btn.update() + + # Adjust size and position + self.lock_btn_tooltip.adjustSize() + self.lock_btn_tooltip.move(tooltip_pos) + self.lock_btn_tooltip.show() + self.lock_btn_tooltip.raise_() + + # Hide after 3 seconds + if not hasattr(self, 'tooltip_timer'): + self.tooltip_timer = QTimer() + self.tooltip_timer.setSingleShot(True) + self.tooltip_timer.timeout.connect(self.lock_btn_tooltip.hide) + self.tooltip_timer.timeout.connect(self.clear_force_hover) + + self.tooltip_timer.start(3000) + + def toggle_lock(self): + self.is_locked = not self.is_locked + self.lock_btn.setChecked(self.is_locked) + self.scroll_area.setDisabled(self.is_locked) + self.update_lock_icon() + + def update_lock_icon(self): + if self.lock_btn: + if self.is_locked: + self.lock_btn.setIcon(QIcon(":/vectors/lock_close.svg")) + else: + self.lock_btn.setIcon(QIcon(":/vectors/lock_open.svg")) + + def resizeEvent(self, event): + super().resizeEvent(event) + # Checking hasattr is only meant to prevent errors, + # while standalone testing of this widget + if self.parent: + if self.width() == 0: + if hasattr(self.parent, 'update_docking_icons'): + self.parent.update_docking_icons(input_is_active=False) + elif self.width() > 0: + if hasattr(self.parent, 'update_docking_icons'): + self.parent.update_docking_icons(input_is_active=True) + + + def paintEvent(self, event): + self.update_lock_icon() + return super().paintEvent(event) + + def toggle_input_dock(self): + parent = self.parent + if hasattr(parent, 'toggle_animate'): + is_collapsing = self.width() > 0 + parent.toggle_animate(show=not is_collapsing, dock='input') + + self.toggle_btn.setText("❯" if is_collapsing else "❮") + self.toggle_btn.setToolTip("Show panel" if is_collapsing else "Hide panel") + + + # Lock-Tooltip-Events-Ends------------------------------------------------------------------------- + + def build_left_panel(self, field_list): + left_layout = QVBoxLayout(self.left_container) + left_layout.setContentsMargins(0, 0, 0, 0) + left_layout.setSpacing(0) + + self.left_panel = QWidget() + self.left_panel.setStyleSheet("background-color: white;") + panel_layout = QVBoxLayout(self.left_panel) + panel_layout.setContentsMargins(15, 10, 15, 10) + panel_layout.setSpacing(0) + + # Top Bar with buttons + top_bar = QHBoxLayout() + top_bar.setSpacing(8) + top_bar.setContentsMargins(0, 0, 0, 15) + + input_dock_btn = QPushButton("Basic Inputs") + input_dock_btn.setStyleSheet(""" + QPushButton { + background-color: #90AF13; + color: white; + font-weight: bold; + font-size: 13px; + border: none; + border-radius: 4px; + padding: 7px 20px; + min-width: 80px; + } + """) + input_dock_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + top_bar.addWidget(input_dock_btn) + + self.additional_inputs_btn = QPushButton("Additional Inputs") + self.additional_inputs_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.additional_inputs_btn.setStyleSheet(""" + QPushButton { + background-color: white; + color: black; + font-weight: bold; + font-size: 13px; + border-radius: 5px; + border: 1px solid black; + padding: 7px 20px; + text-align: center; + } + QPushButton:hover { + background-color: #90AF13; + border: 1px solid #90AF13; + color: white; + } + QPushButton:pressed { + color: black; + background-color: white; + border: 1px solid black; + } + """) + self.additional_inputs_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + self.additional_inputs_btn.clicked.connect(self.show_additional_inputs) + top_bar.addWidget(self.additional_inputs_btn) + + # Lock button + self.lock_btn = QPushButton() + self.lock_btn.setStyleSheet(""" + QPushButton { + background-color: #f4f4f4; + border: none; + padding: 7px; + border-radius: 4px; + } + QPushButton:hover { + background-color: #e0e0e0; + } + QPushButton:checked { + background-color: #FFA500; + } + QPushButton:unchecked { + background-color: #f4f4f4; + } + QPushButton:unchecked:hover { + background-color: #e0e0e0; + } + QPushButton:checked:hover { + background-color: #fa7a02; + } + """) + self.lock_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.lock_btn.setObjectName("lock_btn") + self.lock_btn.setCheckable(True) + self.lock_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.lock_btn.clicked.connect(self.toggle_lock) + top_bar.addWidget(self.lock_btn) + panel_layout.addLayout(top_bar) + + #-Lock-ToolTip-------------------------------------- + self.lock_btn_tooltip = QLabel("Unlock to Edit") + self.lock_btn_tooltip.setStyleSheet(""" + QLabel{ + background-color: #f1f1f1; + color: #000000; + border: 1px solid #90AF13; + padding: 4px; + font-size: 15px; + border-radius: 0px; + qproperty-alignment: AlignVCenter; + } + """) + self.lock_btn_tooltip.setObjectName("lock_btn_tooltip") + self.lock_btn_tooltip.setWindowFlags(Qt.ToolTip) + self.lock_btn_tooltip.hide() + #-------------------------------------------------- + + # Scroll area + scroll_area = QScrollArea() + self.scroll_area = scroll_area + scroll_area.setWidgetResizable(True) + scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) + scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + scroll_area.installEventFilter(self) + scroll_area.setStyleSheet(""" + QScrollArea { + background: transparent; + padding: 0px 5px; + border-top: 1px solid #909090; + border-bottom: 1px solid #909090; + } + + QScrollArea QScrollBar:vertical { + border: none; + background: #f0f0f0; + width: 8px; + margin-left: 2px; + } + + QScrollArea QScrollBar::handle:vertical { + background: #c0c0c0; + border-radius: 4px; + min-height: 20px; + } + + QScrollArea QScrollBar::handle:vertical:hover { + background: #a0a0a0; + } + + QScrollArea QScrollBar::handle:vertical:pressed { + background: #808080; + } + + QScrollArea QScrollBar::add-line:vertical, + QScrollArea QScrollBar::sub-line:vertical { + border: none; + background: none; + } + + QScrollArea QScrollBar::add-page:vertical, + QScrollArea QScrollBar::sub-page:vertical { + background: none; + } + """) + + group_container = QWidget() + self.input_widget = group_container + group_container_layout = QVBoxLayout(group_container) + group_container_layout.setContentsMargins(0, 0, 0, 0) + group_container_layout.setSpacing(12) + + self.section_contexts = {} + self.superstructure_body_layout = None + + self._build_basic_inputs(field_list, group_container_layout) + self._add_substructure_section(group_container_layout) + + group_container_layout.addStretch() + scroll_area.setWidget(group_container) + + self.data = {} + panel_layout.addWidget(scroll_area) + + # Bottom buttons + btn_button_layout = QHBoxLayout() + btn_button_layout.setContentsMargins(0, 15, 0, 0) + btn_button_layout.setSpacing(10) + + save_input_btn = DockCustomButton("Save Input", ":/vectors/save.svg") + save_input_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + btn_button_layout.addWidget(save_input_btn) + + design_btn = DockCustomButton("Design", ":/vectors/design.svg") + design_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + btn_button_layout.addWidget(design_btn) + + panel_layout.addLayout(btn_button_layout) + + # Horizontal scroll area + h_scroll_area = QScrollArea() + h_scroll_area.setWidgetResizable(True) + h_scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) + h_scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + h_scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + h_scroll_area.setStyleSheet(""" + QScrollArea{ + background: transparent; + } + QScrollBar:horizontal{ + background: #E0E0E0; + height: 8px; + margin: 3px 0px 0px 0px; + border-radius: 2px; + } + QScrollBar::handle:horizontal{ + background: #A0A0A0; + min-width: 30px; + border-radius: 2px; + } + QScrollBar::handle:horizontal:hover{ + background: #707070; + } + QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal{ + width: 0px; + } + QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal{ + background: none; + } + """) + h_scroll_area.setWidget(self.left_panel) + + left_layout.addWidget(h_scroll_area) + self._apply_lock_state() + + def _build_basic_inputs(self, field_definitions, root_layout): + current_section_id = None + for definition in field_definitions: + key, label, field_type, values, required, validator, metadata = self._normalize_definition(definition) + if field_type == TYPE_MODULE: + continue + if field_type == TYPE_TITLE: + section_id = key or label + section_context = self._create_section_context(section_id, label, metadata, root_layout) + current_section_id = section_context["id"] + continue + if current_section_id is None: + continue + section_context = self.section_contexts.get(current_section_id) + if not section_context: + continue + self._create_field_row(section_context, key, label, field_type, values, validator, metadata) + + self._finalize_section_contexts() + self._update_carriageway_placeholder() + + def _normalize_definition(self, definition): + if len(definition) == 6: + return (*definition, {}) + return definition + + def _create_section_context(self, section_id, title, metadata, root_layout): + container_key = (metadata or {}).get("container", "main") + parent_layout = self._get_container_layout(container_key, root_layout) + + show_title = metadata.get("show_group_title", True) if metadata else True + group_title = title if show_title and title else "" + group_box = QGroupBox(group_title) if group_title else QGroupBox() + group_box.setStyleSheet(self._section_groupbox_style()) + + layout = QVBoxLayout(group_box) + layout.setContentsMargins(8, 8, 8, 8) + layout.setSpacing(8) + + if metadata and metadata.get("custom_content") == "project_location": + self._add_project_location_controls(layout, metadata) + + parent_layout.addWidget(group_box) + context = { + "id": section_id, + "layout": layout, + "metadata": metadata or {}, + "group_box": group_box, + } + self.section_contexts[section_id] = context + return context + + def _section_groupbox_style(self): + return ( + "QGroupBox {\n" + " border: 1px solid #90AF13;\n" + " border-radius: 4px;\n" + " background-color: white;\n" + " padding: 8px;\n" + " margin-top: 12px;\n" + " font-size: 10px;\n" + " font-weight: bold;\n" + " color: #333;\n" + "}\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + " subcontrol-position: top left;\n" + " left: 8px;\n" + " padding: 0 4px;\n" + " margin-top: 4px;\n" + " background-color: white;\n" + " color: #333;\n" + "}" + ) + + def _get_container_layout(self, container_key, root_layout): + if container_key == "superstructure": + if self.superstructure_body_layout is None: + self.superstructure_body_layout = self._create_superstructure_group(root_layout) + return self.superstructure_body_layout + return root_layout + + def _create_superstructure_group(self, root_layout): + structure_group = QGroupBox() + structure_group.setStyleSheet( + "QGroupBox {\n" + " border: 1px solid #90AF13;\n" + " border-radius: 5px;\n" + " margin-top: 0px;\n" + " padding-top: 5px;\n" + " background-color: white;\n" + "}" + ) + structure_layout = QVBoxLayout() + structure_layout.setContentsMargins(10, 10, 10, 10) + structure_layout.setSpacing(10) + + header = QHBoxLayout() + title = QLabel("Superstructure") + title.setStyleSheet("font-size: 13px; font-weight: bold; color: #333;") + header.addWidget(title) + header.addStretch() + + toggle_btn = QPushButton() + toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + toggle_btn.setCheckable(True) + toggle_btn.setChecked(True) + toggle_btn.setIcon(QIcon(":/vectors/arrow_up_light.svg")) + toggle_btn.setIconSize(QSize(20, 20)) + toggle_btn.setStyleSheet( + "QPushButton {\n" + " background: transparent;\n" + " border: none;\n" + " padding: 2px;\n" + "}\n" + "QPushButton:hover {\n" + " background: transparent;\n" + "}\n" + "QPushButton:pressed {\n" + " background: transparent;\n" + "}" + ) + header.addWidget(toggle_btn) + structure_layout.addLayout(header) + + structure_body = QFrame() + structure_body.setFrameShape(QFrame.NoFrame) + body_layout = QVBoxLayout(structure_body) + body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setSpacing(10) + structure_body.setVisible(True) + structure_layout.addWidget(structure_body) + + def _toggle(checked): + structure_body.setVisible(checked) + toggle_btn.setIcon(QIcon(":/vectors/arrow_up_light.svg" if checked else ":/vectors/arrow_down_light.svg")) + + toggle_btn.toggled.connect(_toggle) + + structure_group.setLayout(structure_layout) + root_layout.addWidget(structure_group) + return body_layout + + def _add_project_location_controls(self, layout, metadata): + label_text = metadata.get("header_label") or "Project Location*" + button_rows = metadata.get("button_rows") + if button_rows: + for row_entry in button_rows: + row_config = self._prepare_button_row_config(row_entry, {"label": label_text}) + if row_config: + self._add_button_row(layout, row_config) + return + + fallback_row = self._prepare_button_row_config("project_location", {"label": label_text}) + self._add_button_row(layout, fallback_row) + + def _section_label_style(self): + return ( + "QLabel {\n" + " color: #000000;\n" + " font-size: 12px;\n" + " background: transparent;\n" + "}" + ) + + def _default_action_button_style(self): + return ( + "QPushButton {\n" + " background-color: #90AF13;\n" + " color: white;\n" + " font-weight: bold;\n" + " border: none;\n" + " border-radius: 4px;\n" + " padding: 8px 20px;\n" + " font-size: 11px;\n" + " min-width: 80px;\n" + "}\n" + "QPushButton:hover {\n" + " background-color: #7a9a12;\n" + "}\n" + "QPushButton:disabled{\n" + " background: #D0D0D0;\n" + " color: #666;\n" + "}" + ) + + def _default_row_config(self, row_type): + mapping = { + "project_location": { + "label": "Project Location*", + "buttons": [ + {"text": "Add Here", "action": "show_project_location_dialog"}, + ], + }, + "additional_geometry": { + "label": "Additional Geometry", + "buttons": [ + {"text": "Modify Here", "action": "show_additional_inputs"}, + ], + }, + "material_properties": { + "label": "Properties", + "buttons": [ + {"text": "Modify Here", "action": "show_material_properties_dialog"}, + ], + }, + } + return mapping.get(row_type, {}) + + def _prepare_button_row_config(self, config_entry, fallback_defaults=None): + fallback_defaults = fallback_defaults or {} + if isinstance(config_entry, str): + config = {"type": config_entry} + else: + config = dict(config_entry or {}) + + row_type = config.get("type") + defaults = self._default_row_config(row_type) + + resolved = {} + resolved.update(defaults) + resolved.update(fallback_defaults) + resolved.update(config) + + if not resolved.get("buttons"): + extra_defaults = self._default_row_config(resolved.get("type")) + if extra_defaults: + resolved.setdefault("buttons", extra_defaults.get("buttons")) + resolved.setdefault("label", extra_defaults.get("label")) + + return resolved if resolved.get("buttons") else None + + def _add_button_row(self, layout, config): + if not config: + return + + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(8) + + label_text = config.get("label") + if label_text: + field_label = QLabel(label_text) + field_label.setStyleSheet(self._section_label_style()) + field_label.setMinimumWidth(config.get("label_min_width", 110)) + row.addWidget(field_label) + + buttons = config.get("buttons", []) + for button_config in buttons: + button = self._create_action_button(button_config) + stretch = button_config.get("stretch", 1 if len(buttons) == 1 else 0) + row.addWidget(button, stretch) + + if config.get("add_stretch", True): + row.addStretch() + + layout.addLayout(row) + + def _create_action_button(self, config): + button = QPushButton(config.get("text", "Action")) + button.setCursor(Qt.CursorShape.PointingHandCursor) + if config.get("size_policy") == "fixed": + button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + else: + button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + + icon_path = config.get("icon") + if icon_path: + button.setIcon(QIcon(icon_path)) + icon_size = config.get("icon_size") + if isinstance(icon_size, (list, tuple)) and len(icon_size) == 2: + button.setIconSize(QSize(icon_size[0], icon_size[1])) + + style = config.get("style") or self._default_action_button_style() + button.setStyleSheet(style) + + tooltip = config.get("tooltip") + if tooltip: + button.setToolTip(tooltip) + + action_name = config.get("action") + callback = getattr(self, action_name, None) if action_name else None + if callable(callback): + button.clicked.connect(callback) + else: + button.setEnabled(False) + + return button + + def _create_field_row(self, section_context, key, label, field_type, values, validator, metadata): + widget = self._create_input_widget(key, field_type, values, validator, metadata) + if widget is None: + return + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(8) + display_label = (metadata or {}).get("label") if metadata else None + field_label = QLabel(display_label or label) + field_label.setStyleSheet(self._section_label_style()) + field_label.setMinimumWidth(110) + row.addWidget(field_label) + row.addWidget(widget, 1) + if metadata.get("add_stretch"): + row.addStretch() + section_context["layout"].addLayout(row) + + def _create_input_widget(self, key, field_type, values, validator, metadata): + if field_type == TYPE_COMBOBOX: + widget = NoScrollComboBox() + apply_field_style(widget) + if values: + widget.addItems(values) + default_value = (metadata or {}).get("default") + if default_value: + idx = widget.findText(default_value) + if idx >= 0: + widget.setCurrentIndex(idx) + elif field_type == TYPE_TEXTBOX: + widget = QLineEdit() + apply_field_style(widget) + validator_instance = self.get_validator(validator) + if validator_instance: + widget.setValidator(validator_instance) + else: + return None + + if key: + widget.setObjectName(key) + self._register_input_widget(key, widget) + self._apply_field_specific_config(key, widget, metadata or {}) + return widget + + def _register_input_widget(self, key, widget): + if key == KEY_STRUCTURE_TYPE: + self.structure_type_combo = widget + elif key == KEY_SPAN: + self.span_input = widget + elif key == KEY_CARRIAGEWAY_WIDTH: + self.carriageway_input = widget + elif key == KEY_INCLUDE_MEDIAN: + self.include_median_combo = widget + elif key == KEY_FOOTPATH: + self.footpath_combo = widget + elif key == KEY_SKEW_ANGLE: + self.skew_input = widget + elif key == KEY_GIRDER: + self.girder_combo = widget + elif key == KEY_CROSS_BRACING: + self.cross_bracing_combo = widget + elif key == KEY_END_DIAPHRAGM: + self.end_diaphragm_combo = widget + elif key == KEY_DECK_CONCRETE_GRADE_BASIC: + self.deck_combo = widget + + def _apply_field_specific_config(self, key, widget, metadata): + if not key or widget is None: + return + if key == KEY_STRUCTURE_TYPE and hasattr(widget, "currentTextChanged"): + widget.currentTextChanged.connect(self.on_structure_type_changed) + elif key == KEY_SPAN and isinstance(widget, QLineEdit): + widget.setValidator(QDoubleValidator(SPAN_MIN, SPAN_MAX, 2)) + widget.setPlaceholderText(f"{SPAN_MIN}-{SPAN_MAX} m") + elif key == KEY_CARRIAGEWAY_WIDTH and isinstance(widget, QLineEdit): + widget.setValidator(QDoubleValidator(0.0, 100.0, 2)) + widget.editingFinished.connect(self.validate_carriageway_width) + elif key == KEY_INCLUDE_MEDIAN and hasattr(widget, "currentTextChanged"): + widget.currentTextChanged.connect(self.on_include_median_changed) + default_value = metadata.get("default") + if default_value: + idx = widget.findText(default_value) + if idx >= 0: + widget.setCurrentIndex(idx) + elif key == KEY_FOOTPATH and hasattr(widget, "currentTextChanged"): + widget.currentTextChanged.connect(self.on_footpath_changed) + default_value = metadata.get("default") + if default_value: + idx = widget.findText(default_value) + if idx >= 0: + widget.setCurrentIndex(idx) + elif key == KEY_SKEW_ANGLE and isinstance(widget, QLineEdit): + widget.setValidator(QDoubleValidator(SKEW_ANGLE_MIN, SKEW_ANGLE_MAX, 1)) + widget.setPlaceholderText(f"{SKEW_ANGLE_MIN} - {SKEW_ANGLE_MAX}°") + elif key == KEY_DECK_CONCRETE_GRADE_BASIC and hasattr(widget, "findText"): + default_value = metadata.get("default") + if default_value: + idx = widget.findText(default_value) + if idx >= 0: + widget.setCurrentIndex(idx) + + def _finalize_section_contexts(self): + for context in self.section_contexts.values(): + metadata = context.get("metadata", {}) + note_config = metadata.get("post_note") + if note_config: + self._add_section_note(context, note_config) + + for row_entry in metadata.get("post_rows", []): + row_config = self._prepare_button_row_config(row_entry) + if row_config: + self._add_button_row(context["layout"], row_config) + + def _add_section_note(self, context, note_config): + note_label = QLabel(note_config.get("text", "")) + note_label.setStyleSheet(self._section_label_style()) + note_label.setVisible(False) + context["layout"].addWidget(note_label) + attr_name = note_config.get("attr") + if attr_name: + setattr(self, attr_name, note_label) + + + def _add_substructure_section(self, parent_layout): + sub_group = QGroupBox() + sub_group.setStyleSheet( + "QGroupBox {\n" + " border: 1px solid #90AF13;\n" + " border-radius: 5px;\n" + " margin-top: 8px;\n" + " padding-top: 5px;\n" + " background-color: white;\n" + "}" + ) + sub_layout = QVBoxLayout() + sub_layout.setContentsMargins(10, 10, 10, 10) + sub_layout.setSpacing(8) + + header = QHBoxLayout() + header.setContentsMargins(0, 0, 0, 0) + header.setSpacing(8) + title = QLabel("Substructure") + title.setStyleSheet("font-size: 13px; font-weight: bold; color: #333;") + header.addWidget(title) + header.addStretch() + + toggle_btn = QPushButton() + toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + toggle_btn.setCheckable(True) + toggle_btn.setChecked(True) + toggle_btn.setIcon(QIcon(":/vectors/arrow_up_light.svg")) + toggle_btn.setIconSize(QSize(20, 20)) + toggle_btn.setStyleSheet( + "QPushButton {\n" + " background: transparent;\n" + " border: none;\n" + " padding: 2px;\n" + "}\n" + "QPushButton:hover {\n" + " background: transparent;\n" + "}\n" + "QPushButton:pressed {\n" + " background: transparent;\n" + "}" + ) + header.addWidget(toggle_btn) + sub_layout.addLayout(header) + + sub_body = QFrame() + sub_body.setFrameShape(QFrame.NoFrame) + sub_body_layout = QVBoxLayout(sub_body) + sub_body_layout.setContentsMargins(0, 0, 0, 0) + sub_body_layout.setSpacing(6) + sub_body.setVisible(True) + sub_layout.addWidget(sub_body) + + def _toggle(checked): + sub_body.setVisible(checked) + toggle_btn.setIcon(QIcon(":/vectors/arrow_up_light.svg" if checked else ":/vectors/arrow_down_light.svg")) + + toggle_btn.toggled.connect(_toggle) + + sub_group.setLayout(sub_layout) + parent_layout.addWidget(sub_group) + + def show_additional_inputs(self): + """Show Additional Inputs dialog""" + footpath_value = self.footpath_combo.currentText() if self.footpath_combo else "None" + + carriageway_width = self._get_effective_carriageway_width() + + self.additional_inputs = AdditionalInputs(footpath_value, carriageway_width) + self.additional_inputs.show() + + def _apply_lock_state(self): + self.update_lock_icon() + + enabled = not self.is_locked + if self.scroll_area: + self.scroll_area.setEnabled(enabled) + if self.input_widget: + self.input_widget.setEnabled(enabled) + self._set_additional_inputs_enabled(enabled) + + if self.material_dialog: + self.material_dialog.setEnabled(enabled) + + def _set_additional_inputs_enabled(self, enabled): + if self.additional_inputs_widget: + self.additional_inputs_widget.setEnabled(enabled) + + def _handle_additional_inputs_closed(self): + self.additional_inputs = None + self.additional_inputs_widget = None + + def on_footpath_changed(self, footpath_value): + """Update additional inputs when footpath changes""" + if self.additional_inputs and self.additional_inputs.isVisible(): + if hasattr(self, 'additional_inputs_widget'): + self.additional_inputs_widget.update_footpath_value(footpath_value) + + def on_include_median_changed(self, _value): + self._update_carriageway_placeholder() + # Re-validate silently so previously entered values honor the new limits + self.validate_carriageway_width(show_message=False) + + def _carriageway_limits(self): + include_median = self._is_median_included() + min_width = CARRIAGEWAY_WIDTH_MIN_WITH_MEDIAN if include_median else CARRIAGEWAY_WIDTH_MIN + return min_width, CARRIAGEWAY_WIDTH_MAX_LIMIT + + def _update_carriageway_placeholder(self): + if not hasattr(self, "carriageway_input") or self.carriageway_input is None: + return + min_width, max_width = self._carriageway_limits() + suffix = " per side" if self._is_median_included() else "" + self.carriageway_input.setPlaceholderText(f"{min_width:.2f} - {max_width:.1f} m{suffix}") + + def validate_carriageway_width(self, show_message=True): + if not self.carriageway_input: + return + text = self.carriageway_input.text().strip() + if not text: + return + try: + value = float(text) + except ValueError: + self.carriageway_input.clear() + if show_message: + QMessageBox.warning(self, "Carriageway Width", "Please enter a numeric carriageway width.") + return + + min_width, max_width = self._carriageway_limits() + include_median = self._is_median_included() + message = None + + if value < min_width: + if include_median: + message = "IRC 5 Clause 104.3.1 requires minimum carriageway width on both sides of the median to be at least 7.5 m." + else: + message = "IRC 5 Clause 104.3.1 requires minimum carriageway width of 4.25 m." + value = min_width + elif value > max_width: + message = "Software limits carriageway width upto 23.6 m" + value = max_width + + self.carriageway_input.setText(f"{value:.2f}") + if message and show_message: + QMessageBox.warning(self, "Carriageway Width", message) + + def _get_effective_carriageway_width(self): + min_width, max_width = self._carriageway_limits() + width = min_width + if self.carriageway_input and self.carriageway_input.text(): + try: + width = float(self.carriageway_input.text()) + except ValueError: + width = min_width + width = max(min_width, min(width, max_width)) + if self._is_median_included(): + return width * 2.0 # Two carriageways, one on each side of the median + return width + + def _is_median_included(self): + if not self.include_median_combo: + return False + return self.include_median_combo.currentText().lower() == "yes" + + def show_material_properties_dialog(self): + """Open the material properties dialog with the relevant member selected.""" + if self.material_dialog is None: + self.material_dialog = MaterialPropertiesDialog(self) + + member = "Girder" + focus_widget = QApplication.focusWidget() + focus_map = { + getattr(self, 'girder_combo', None): "Girder", + getattr(self, 'deck_combo', None): "Deck", + getattr(self, 'cross_bracing_combo', None): "Cross Bracing", + getattr(self, 'end_diaphragm_combo', None): "End Diaphragm", + } + for widget, name in focus_map.items(): + if widget is not None and widget is focus_widget: + member = name + break + + self.material_dialog.sync_with_parent_defaults() + self.material_dialog.set_member(member) + self.material_dialog.show() + self.material_dialog.raise_() + self.material_dialog.activateWindow() \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/docks/log_dock.py b/src/osdagbridge/desktop/ui/docks/log_dock.py new file mode 100644 index 00000000..37f28d33 --- /dev/null +++ b/src/osdagbridge/desktop/ui/docks/log_dock.py @@ -0,0 +1,88 @@ +""" +Log dock widget for Osdag GUI. +Displays log messages and status updates. +""" +from PySide6.QtWidgets import QWidget, QVBoxLayout, QTextEdit, QLabel +from PySide6.QtCore import Qt, QDateTime + +class LogDock(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + # Ensures automatic deletion when closed + self.setAttribute(Qt.WA_DeleteOnClose, True) + self.is_visible = True + self.setObjectName("logs_dock") + self.init_ui() + self.adjust_size() + + def init_ui(self): + # Create layout for the log dock + layout = QVBoxLayout(self) + layout.setContentsMargins(5, 2, 5, 0) + layout.setSpacing(0) + + # Create a top strip for "Log Window" + self.log_window_title = QLabel("Log Window") + self.log_window_title.setAlignment(Qt.AlignLeft) + layout.addWidget(self.log_window_title) + + # Create log display area + self.log_display = QTextEdit() + self.log_display.setObjectName("textEdit") + self.log_display.setReadOnly(True) + self.log_display.setOverwriteMode(True) + layout.addWidget(self.log_display) + + # Add init log text matching + self.append_log(f"[{QDateTime.currentDateTime().toString('yyyy-MM-dd hh:mm:ss')}] Log initialized", "info") + + self.setLayout(layout) + self.show() # Show init text + + def append_log(self, message, log_level="info"): + """Append a message to the log display with specified color.""" + if log_level == "error": + color = "#FF0000" # Red for errors + elif log_level == "info": + color = "#A6A6A6" # Black for info + elif log_level == "success": + color = "#008000" # Green for success + + formatted_message = f"{message}" + self.log_display.append(formatted_message) + self.log_display.ensureCursorVisible() + + def toggle_log_dock(self): + """Toggle the visibility of the log dock.""" + self.is_visible = not self.is_visible + if self.is_visible: + self.show() + self.adjust_size() + self.move(0, self.parent().height() - self.height()) + else: + self.hide() + + def adjust_size(self): + """Adjust the size of the log dock based on input and output dock states.""" + parent = self.parent() + if not parent: + return + if parent.input_dock is None or parent.output_dock is None: + return + + input_dock = parent.input_dock + output_dock = parent.output_dock + + # Calculate available width + parent_width = parent.width() + input_dock_width = input_dock.width() if input_dock.isVisible() else 0 + output_dock_width = output_dock.width() if output_dock.isVisible() else 0 + available_width = parent_width - input_dock_width - output_dock_width + + # Set log dock size + default_height = 150 # Fixed height for log dock + self.setFixedSize(available_width, default_height) + + # Update position if visible + if self.is_visible: + self.move(0, parent.height() - default_height) \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/docks/output_dock.py b/src/osdagbridge/desktop/ui/docks/output_dock.py new file mode 100644 index 00000000..9ec492fc --- /dev/null +++ b/src/osdagbridge/desktop/ui/docks/output_dock.py @@ -0,0 +1,578 @@ +from PySide6.QtWidgets import ( + QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, + QPushButton, QGroupBox, QCheckBox, QScrollArea, QFrame, QComboBox, QLineEdit +) +from PySide6.QtCore import Qt, QSize +from PySide6.QtGui import QIcon + +from osdagbridge.desktop.ui.utils.custom_buttons import DockCustomButton +from osdagbridge.core.utils.common import TYPE_TITLE + +class NoScrollComboBox(QComboBox): + def wheelEvent(self, event): + event.ignore() # Prevent changing selection on scroll + +def apply_field_style(widget): + widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + widget.setMinimumHeight(28) + if isinstance(widget, QComboBox): + style = """ + QComboBox{ + padding: 1px 7px; + border: 1px solid black; + border-radius: 5px; + background-color: white; + color: black; + } + QComboBox::drop-down{ + subcontrol-origin: padding; + subcontrol-position: top right; + border-left: 0px; + } + QComboBox::down-arrow{ + image: url(:/vectors/arrow_down_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox::down-arrow:on { + image: url(:/vectors/arrow_up_light.svg); + width: 20px; + height: 20px; + margin-right: 8px; + } + QComboBox QAbstractItemView{ + background-color: white; + border: 1px solid black; + outline: none; + } + QComboBox QAbstractItemView::item{ + color: black; + background-color: white; + border: none; + border: 1px solid white; + border-radius: 0; + padding: 2px; + } + QComboBox QAbstractItemView::item:hover{ + border: 1px solid #90AF13; + background-color: #90AF13; + color: black; + } + QComboBox QAbstractItemView::item:selected{ + background-color: #90AF13; + color: black; + border: 1px solid #90AF13; + } + QComboBox QAbstractItemView::item:selected:hover{ + background-color: #90AF13; + color: black; + border: 1px solid #94b816; + } + """ + widget.setStyleSheet(style) + elif isinstance(widget, QLineEdit): + widget.setStyleSheet(""" + QLineEdit { + padding: 1px 7px; + border: 1px solid #070707; + border-radius: 6px; + background-color: white; + color: #000000; + font-weight: normal; + } + """) + +class OutputDock(QWidget): + """Output dock with collapsible design controls and scrollable layout.""" + + def __init__(self, backend=None, parent=None): + super().__init__() + self.parent = parent + self.backend = backend + self.setStyleSheet("background: transparent;") + configs = self._load_configs() + self.analysis_config = configs.get("analysis") + # Configurable button rows per section; populated from backend ui_fields + self.section_configs = configs.get("design", []) + self.init_ui() + + def toggle_output_dock(self): + parent = self.parent + if hasattr(parent, 'toggle_animate'): + is_collapsing = self.width() > 0 + parent.toggle_animate(show=not is_collapsing, dock='output') + + self.toggle_btn.setText("❮" if is_collapsing else "❯") + self.toggle_btn.setToolTip("Show panel" if is_collapsing else "Hide panel") + + def resizeEvent(self, event): + super().resizeEvent(event) + # Checking hasattr is only meant to prevent errors + if self.parent: + if self.width() == 0: + if hasattr(self.parent, 'update_docking_icons'): + self.parent.update_docking_icons(output_is_active=False) + elif self.width() > 0: + if hasattr(self.parent, 'update_docking_icons'): + self.parent.update_docking_icons(output_is_active=True) + + + def init_ui(self): + # Main horizontal layout to hold toggle strip and content + self.main_layout = QHBoxLayout(self) + self.main_layout.setContentsMargins(0, 0, 0, 0) + self.main_layout.setSpacing(0) + + # Toggle strip on the left + self.toggle_strip = QWidget() + self.toggle_strip.setStyleSheet("background-color: #90AF13;") + self.toggle_strip.setFixedWidth(6) + toggle_layout = QVBoxLayout(self.toggle_strip) + toggle_layout.setContentsMargins(0, 0, 0, 0) + toggle_layout.setSpacing(0) + toggle_layout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) + + self.toggle_btn = QPushButton("❯") + self.toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.toggle_btn.setFixedSize(6, 60) + self.toggle_btn.setToolTip("Hide panel") + self.toggle_btn.clicked.connect(self.toggle_output_dock) + self.toggle_btn.setStyleSheet(""" + QPushButton { + background-color: #7a9a12; + color: white; + font-size: 12px; + font-weight: bold; + padding: 0px; + border: none; + } + QPushButton:hover { + background-color: #6a8a10; + } + """) + toggle_layout.addStretch() + toggle_layout.addWidget(self.toggle_btn) + toggle_layout.addStretch() + self.main_layout.addWidget(self.toggle_strip) + + # Content container + content_container = QWidget() + content_container.setStyleSheet("background-color: white;") + content_layout = QVBoxLayout(content_container) + content_layout.setContentsMargins(8, 8, 8, 8) + content_layout.setSpacing(10) + + # Top Bar with buttons + top_bar = QHBoxLayout() + top_bar.setSpacing(8) + top_bar.setContentsMargins(0, 0, 0, 15) + + input_dock_btn = QPushButton("Output Dock") + input_dock_btn.setStyleSheet(""" + QPushButton { + background-color: #90AF13; + color: white; + font-weight: bold; + font-size: 13px; + border: none; + border-radius: 4px; + padding: 7px 20px; + min-width: 80px; + } + """) + input_dock_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + top_bar.addWidget(input_dock_btn) + top_bar.addStretch() + content_layout.addLayout(top_bar) + + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setStyleSheet("QScrollArea { border: none; background: white; }") + + scroll_content = QWidget() + scroll_layout = QVBoxLayout(scroll_content) + scroll_layout.setContentsMargins(0, 0, 0, 0) + scroll_layout.setSpacing(10) + + analysis_group = self._build_analysis_group() + if analysis_group: + scroll_layout.addWidget(analysis_group) + + design_group = QGroupBox("Design") + design_group.setStyleSheet( + """ + QGroupBox { + font-weight: bold; + font-size: 11px; + color: #333; + border: 1px solid #90AF13; + border-radius: 4px; + margin-top: 8px; + padding-top: 12px; + background-color: white; + } + QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 8px; + padding: 0 4px; + background-color: white; + } + """ + ) + design_layout = QVBoxLayout(design_group) + design_layout.setContentsMargins(10, 8, 10, 10) + design_layout.setSpacing(8) + + # Dynamic design sections + for section_cfg in self.section_configs: + section_group = self._create_toggle_group(section_cfg) + design_layout.addWidget(section_group) + + scroll_layout.addWidget(design_group) + scroll_layout.addStretch() + + scroll.setWidget(scroll_content) + content_layout.addWidget(scroll) + + h_layout = QHBoxLayout() + h_layout.setSpacing(5) + h_layout.setContentsMargins(0, 0, 0, 0) + + results_btn = DockCustomButton("Generate Results Table", ":/vectors/design_report.svg") + results_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + h_layout.addWidget(results_btn) + + report_btn = DockCustomButton("Generate Report", ":/vectors/design_report.svg") + report_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + + h_layout.addWidget(report_btn) + content_layout.addLayout(h_layout) + + # Add content container to main layout + self.main_layout.addWidget(content_container) + + def show_additional_inputs(self): + """Handle showing additional geometry inputs.""" + # Implement your logic here + print("Show additional inputs clicked") + + # --- Helpers for dynamic section/button rendering --- + def _load_configs(self): + if self.backend and hasattr(self.backend, "output_values"): + try: + cfg = self.backend.output_values(flag=None) + if cfg is not None: + return self._normalize_section_configs(cfg) + except Exception: + pass + return {"analysis": None, "design": []} + + def _normalize_section_configs(self, cfg): + result = {"analysis": None, "design": []} + if not cfg: + return result + + # Already structured dict + if isinstance(cfg, dict): + result["analysis"] = cfg.get("analysis") + if isinstance(cfg.get("design"), list): + result["design"] = cfg.get("design") + return result + + # Legacy dict list: treat as design-only + if isinstance(cfg, list) and all(isinstance(item, dict) for item in cfg): + result["design"] = cfg + return result + + # Tuple-based definitions similar to input_values + if isinstance(cfg, list) and all(isinstance(item, tuple) for item in cfg): + for item in cfg: + if len(item) < 7: + continue + _, display_name, ui_type, _, is_visible, _, metadata = item + if ui_type != TYPE_TITLE or not is_visible: + continue + metadata = metadata or {} + kind = metadata.get("kind", "design") + if kind == "analysis": + result["analysis"] = { + "title": display_name, + "fields": metadata.get("fields", []), + } + continue + rows = metadata.get("rows") or metadata.get("post_rows") or [] + if not isinstance(rows, list): + rows = [] + result["design"].append({"title": display_name, "rows": rows}) + return result + + return result + + def _default_analysis_config(self): + return { + "title": "Analysis Results", + "fields": [ + {"type": "combobox", "label": "Member:", "values": ["All"]}, + { + "type": "combobox", + "label": "Load Combination:", + "values": ["Envelope"], + }, + { + "type": "checkbox_grid", + "columns": [["Fx", "Mx", "Dx"], ["Fy", "My", "Dy"], ["Fz", "Mz", "Dz"]], + }, + { + "type": "checkbox_row", + "label": "Display Options:", + "options": ["Max", "Min"], + }, + {"type": "checkbox", "label": "Controlling Utilization Ratio"}, + ], + } + + def _analysis_group_style(self): + return ( + "QGroupBox {\n" + " font-weight: bold;\n" + " font-size: 11px;\n" + " color: #333;\n" + " border: 1px solid #90AF13;\n" + " border-radius: 4px;\n" + " margin-top: 8px;\n" + " padding-top: 12px;\n" + " background-color: white;\n" + "}\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + " subcontrol-position: top left;\n" + " left: 8px;\n" + " padding: 0 4px;\n" + " background-color: white;\n" + "}" + ) + + def _build_analysis_group(self): + cfg = self.analysis_config or self._default_analysis_config() + if not cfg: + return None + + group = QGroupBox(cfg.get("title", "Analysis Results")) + group.setStyleSheet(self._analysis_group_style()) + layout = QVBoxLayout(group) + layout.setContentsMargins(10, 8, 10, 10) + layout.setSpacing(8) + + for field_cfg in cfg.get("fields", []): + self._add_analysis_field(layout, field_cfg) + + return group + + def _normalize_field_cfg(self, field_cfg): + if isinstance(field_cfg, dict): + return field_cfg + if isinstance(field_cfg, tuple) and len(field_cfg) >= 7: + key, label, field_type, values, is_visible, _validator, metadata = field_cfg + if not is_visible: + return None + meta = metadata or {} + normalized = { + "key": key, + "label": label, + "type": field_type, + "values": values, + } + normalized.update(meta) + return normalized + return None + + def _add_analysis_field(self, layout, field_cfg): + cfg = self._normalize_field_cfg(field_cfg) + if not cfg: + return + field_type = cfg.get("type") + if field_type == "combobox": + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(8) + label = QLabel(cfg.get("label", "")) + label.setStyleSheet("font-size: 10px; color: #333; font-weight: normal;") + label.setMinimumWidth(cfg.get("label_min_width", 100)) + combo = NoScrollComboBox() + values = cfg.get("values") or [] + combo.addItems(values) + default = cfg.get("default") + if default and default in values: + combo.setCurrentText(default) + apply_field_style(combo) + row.addWidget(label) + row.addWidget(combo) + layout.addLayout(row) + elif field_type == "checkbox_grid": + columns = cfg.get("columns") or cfg.get("values") or [] + grid = QHBoxLayout() + grid.setContentsMargins(0, 0, 0, 0) + grid.setSpacing(8) + for col_items in columns: + col_layout = QVBoxLayout() + col_layout.setContentsMargins(0, 0, 0, 0) + col_layout.setSpacing(2) + for text in col_items or []: + cb = QCheckBox(str(text)) + col_layout.addWidget(cb) + grid.addLayout(col_layout) + if cfg.get("add_stretch", True): + grid.addStretch() + layout.addLayout(grid) + elif field_type == "checkbox_row": + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(12) + label = cfg.get("label") + if label: + lbl = QLabel(label) + lbl.setStyleSheet("font-size: 10px; color: #333; font-weight: normal; margin-top: 4px;") + row.addWidget(lbl) + options = cfg.get("options") or cfg.get("values") or [] + for text in options: + cb = QCheckBox(str(text)) + row.addWidget(cb) + if cfg.get("add_stretch", True): + row.addStretch() + layout.addLayout(row) + elif field_type == "checkbox": + cb = QCheckBox(cfg.get("label", "")) + layout.addWidget(cb) + + def _section_label_style(self): + return ( + "QLabel {\n" + " color: #000000;\n" + " font-size: 12px;\n" + " background: transparent;\n" + "}" + ) + + def _default_action_button_style(self): + return ( + "QPushButton {\n" + " background-color: #90AF13;\n" + " color: white;\n" + " font-weight: bold;\n" + " border: none;\n" + " border-radius: 4px;\n" + " padding: 8px 20px;\n" + " font-size: 11px;\n" + " min-width: 80px;\n" + "}\n" + "QPushButton:hover {\n" + " background-color: #7a9a12;\n" + "}\n" + ) + + def _create_action_button(self, cfg): + btn = QPushButton(cfg.get("text", "Action")) + btn.setCursor(Qt.CursorShape.PointingHandCursor) + btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + style = cfg.get("style") or self._default_action_button_style() + btn.setStyleSheet(style) + if cfg.get("icon"): + btn.setIcon(QIcon(cfg["icon"])) + icon_size = cfg.get("icon_size") + if isinstance(icon_size, (list, tuple)) and len(icon_size) == 2: + btn.setIconSize(QSize(icon_size[0], icon_size[1])) + cb_name = cfg.get("action") + cb = getattr(self, cb_name, None) if cb_name else None + if callable(cb): + btn.clicked.connect(cb) + else: + btn.setEnabled(False) + return btn + + def _add_button_row(self, parent_layout, row_cfg): + row = QHBoxLayout() + row.setContentsMargins(0, 0, 0, 0) + row.setSpacing(8) + + label_text = row_cfg.get("label") + if label_text: + label = QLabel(label_text) + label.setStyleSheet(self._section_label_style()) + label.setMinimumWidth(row_cfg.get("label_min_width", 110)) + row.addWidget(label) + + buttons = row_cfg.get("buttons", []) + for cfg in buttons: + btn = self._create_action_button(cfg) + row.addWidget(btn, cfg.get("stretch", 1 if len(buttons) == 1 else 0)) + + if row_cfg.get("add_stretch", True): + row.addStretch() + + parent_layout.addLayout(row) + + def _create_toggle_group(self, section_cfg): + group = QGroupBox() + group.setStyleSheet( + "QGroupBox {\n" + " border: 1px solid #90AF13;\n" + " border-radius: 5px;\n" + " margin-top: 0px;\n" + " padding-top: 5px;\n" + " background-color: white;\n" + "}" + ) + layout = QVBoxLayout() + layout.setContentsMargins(10, 10, 10, 10) + layout.setSpacing(10) + + header = QHBoxLayout() + title = QLabel(section_cfg.get("title", "")) + title.setStyleSheet("font-size: 13px; font-weight: bold; color: #333;") + header.addWidget(title) + header.addStretch() + + toggle_btn = QPushButton() + toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + toggle_btn.setCheckable(True) + toggle_btn.setChecked(True) + toggle_btn.setIcon(QIcon(":/vectors/arrow_up_light.svg")) + toggle_btn.setIconSize(QSize(20, 20)) + toggle_btn.setStyleSheet( + "QPushButton {\n" + " background: transparent;\n" + " border: none;\n" + " padding: 2px;\n" + "}\n" + "QPushButton:hover {\n" + " background: transparent;\n" + "}\n" + "QPushButton:pressed {\n" + " background: transparent;\n" + "}" + ) + header.addWidget(toggle_btn) + layout.addLayout(header) + + body = QFrame() + body.setFrameShape(QFrame.NoFrame) + body_layout = QVBoxLayout(body) + body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setSpacing(10) + body.setVisible(True) + + for row_cfg in section_cfg.get("rows", []): + self._add_button_row(body_layout, row_cfg) + + layout.addWidget(body) + + def _toggle(checked): + body.setVisible(checked) + toggle_btn.setIcon(QIcon(":/vectors/arrow_up_light.svg" if checked else ":/vectors/arrow_down_light.svg")) + + toggle_btn.toggled.connect(_toggle) + group.setLayout(layout) + return group \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/main_window.ui b/src/osdagbridge/desktop/ui/main_window.ui deleted file mode 100644 index b52aea53..00000000 --- a/src/osdagbridge/desktop/ui/main_window.ui +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/osdagbridge/desktop/ui/template_page.py b/src/osdagbridge/desktop/ui/template_page.py new file mode 100644 index 00000000..1cf942fc --- /dev/null +++ b/src/osdagbridge/desktop/ui/template_page.py @@ -0,0 +1,683 @@ +import sys +from PySide6.QtWidgets import ( + QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, + QMenuBar, QSplitter, QSizePolicy, QPushButton, QScrollArea, QFrame, +) +from PySide6.QtSvgWidgets import QSvgWidget +from PySide6.QtCore import Qt, QFile, QTextStream, Signal +from PySide6.QtGui import QIcon, QAction, QKeySequence + +from osdagbridge.desktop.ui.docks.input_dock import InputDock +from osdagbridge.desktop.ui.docks.output_dock import OutputDock +from osdagbridge.desktop.ui.docks.log_dock import LogDock + +from osdagbridge.core.bridge_types.plate_girder.ui_fields import FrontendData +from osdagbridge.core.utils.common import * + +class DummyCADWidget(QWidget): + """Placeholder for CAD widget""" + + def __init__(self): + super().__init__() + layout = QVBoxLayout(self) + layout.setContentsMargins(5, 2, 5, 0) + layout.setSpacing(0) + label = QLabel("CAD Window\n(Placeholder)") + label.setAlignment(Qt.AlignCenter) + label.setStyleSheet( + """ + QLabel { + background-color: #f0f0f0; + border: 1px solid #999; + padding: 40px; + font-size: 18px; + color: #666; + } + """ + ) + layout.addWidget(label) + +class CustomWindow(QWidget): + def __init__(self, title: str, backend: object, parent=None): + super().__init__() + self.parent = parent + self.backend = backend() + + self.setWindowTitle(title) + self.setStyleSheet( + """ + QWidget { + background-color: #ffffff; + margin: 0px; + padding: 0px; + } + QMenuBar { + background-color: #F4F4F4; + color: #000000; + padding: 0px; + } + QMenuBar::item { + padding: 5px 10px; + background: transparent; + } + QMenuBar::item:selected { + background: #FFFFFF; + } + """ + ) + self.input_dock = None + self.output_dock = None + + self.init_ui() + + def init_ui(self): + # Docking icons Parent class + class ClickableSvgWidget(QSvgWidget): + clicked = Signal() # Define a custom clicked signal + def __init__(self, parent=None): + super().__init__(parent) + self.setCursor(Qt.CursorShape.PointingHandCursor) + + def mousePressEvent(self, event): + if event.button() == Qt.MouseButton.LeftButton: + self.clicked.emit() # Emit the clicked signal on left-click + super().mousePressEvent(event) + + main_v_layout = QVBoxLayout(self) + main_v_layout.setContentsMargins(0, 0, 0, 0) + main_v_layout.setSpacing(0) + + menu_h_layout = QHBoxLayout() + menu_h_layout.setContentsMargins(0, 0, 0, 0) + menu_h_layout.setSpacing(0) + + self.menu_bar = QMenuBar(self) + self.menu_bar.setObjectName("template_page_menu_bar") + self.menu_bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) + self.menu_bar.setFixedHeight(28) + self.menu_bar.setContentsMargins(0, 0, 0, 0) + menu_h_layout.addWidget(self.menu_bar) + + # Control buttons + control_btn_widget = QWidget() + control_btn_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + control_btn_widget.setObjectName("control_btn_widget") + control_button_layout = QHBoxLayout(control_btn_widget) + control_button_layout.setSpacing(10) + control_button_layout.setContentsMargins(5,5,5,5) + + self.input_dock_control = ClickableSvgWidget() + self.input_dock_control.setFixedSize(18, 18) + self.input_dock_control.load(":/vectors/input_dock_active_light.svg") + self.input_dock_control.clicked.connect(self.input_dock_toggle) + self.input_dock_active = True + control_button_layout.addWidget(self.input_dock_control) + + self.log_dock_control = ClickableSvgWidget() + self.log_dock_control.load(":/vectors/logs_dock_inactive_light.svg") + self.log_dock_control.setFixedSize(18, 18) + self.log_dock_control.clicked.connect(self.logs_dock_toggle) + self.log_dock_active = False + control_button_layout.addWidget(self.log_dock_control) + + self.output_dock_control = ClickableSvgWidget() + self.output_dock_control.load(":/vectors/output_dock_inactive_light.svg") + self.output_dock_control.setFixedSize(18, 18) + self.output_dock_control.clicked.connect(self.output_dock_toggle) + self.output_dock_active = False + control_button_layout.addWidget(self.output_dock_control) + + menu_h_layout.addWidget(control_btn_widget) + main_v_layout.addLayout(menu_h_layout) + self.create_menu_bar_items() + + self.body_widget = QWidget() + self.layout = QHBoxLayout(self.body_widget) + self.layout.setContentsMargins(0, 0, 0, 0) + self.layout.setSpacing(0) + + self.splitter = QSplitter(Qt.Horizontal, self.body_widget) + self.splitter.setHandleWidth(2) + self.input_dock = InputDock(backend=self.backend, parent=self) + input_dock_width = self.input_dock.sizeHint().width() + self._input_dock_default_width = input_dock_width + self.splitter.addWidget(self.input_dock) + + central_widget = QWidget() + central_H_layout = QHBoxLayout(central_widget) + + # Add dock indicator labels + self.input_dock_label = InputDockIndicator(parent=self) + self.input_dock_label.setVisible(False) + central_H_layout.setContentsMargins(0, 0, 0, 0) + central_H_layout.setSpacing(0) + central_H_layout.addWidget(self.input_dock_label, 1) + + central_V_layout = QVBoxLayout() + central_V_layout.setContentsMargins(0, 0, 0, 0) + central_V_layout.setSpacing(0) + + # Add cad component checkboxes + self.cad_comp_widget = DummyCADWidget() + central_V_layout.addWidget(self.cad_comp_widget) + + self.cad_log_splitter = QSplitter(Qt.Vertical) + self.cad_log_splitter.setHandleWidth(2) + # Add Cad Model Widget + self.cad_log_splitter.addWidget(self.cad_comp_widget) + + self.logs_dock = LogDock(parent=self) + self.logs_dock.setVisible(False) + # log text + self.textEdit = self.logs_dock.log_display + self.cad_log_splitter.addWidget(self.logs_dock) + + # Prefer stretch factors so ratio persists on resize + self.cad_log_splitter.setStretchFactor(0, 8) + self.cad_log_splitter.setStretchFactor(1, 1) + # Seed an initial 8:1 split; will be refined after first show + self.cad_log_splitter.setSizes([8, 1]) + + central_V_layout.addWidget(self.cad_log_splitter) + central_H_layout.addLayout(central_V_layout, 6) + + # Add output dock indicator label + self.output_dock_label = OutputDockIndicator(parent=self) + self.output_dock_label.setVisible(True) + central_H_layout.addWidget(self.output_dock_label, 1) + self.splitter.addWidget(central_widget) + + # root is the greatest level of parent that is the MainWindow + self.output_dock = OutputDock(backend=self.backend, parent=self) + self.splitter.addWidget(self.output_dock) + # self.output_dock.setStyleSheet(self.output_dock.styleSheet()) + self.output_dock.hide() + + self.layout.addWidget(self.splitter) + + total_width = self.width() - self.splitter.contentsMargins().left() - self.splitter.contentsMargins().right() + target_sizes = [0] * self.splitter.count() + target_sizes[0] = input_dock_width + target_sizes[2] = 0 + remaining_width = total_width - input_dock_width + target_sizes[1] = max(0, remaining_width) + self.splitter.setSizes(target_sizes) + self.layout.activate() + main_v_layout.addWidget(self.body_widget) + + #---------------------------------Docking-Icons-Functionality-START---------------------------------------------- + + def input_dock_toggle(self): + self.input_dock.toggle_input_dock() + + def output_dock_toggle(self): + self.output_dock.toggle_output_dock() + + def logs_dock_toggle(self): + self.log_dock_active = not self.log_dock_active + self.logs_dock.setVisible(self.log_dock_active) + if self.log_dock_active: + self.log_dock_control.load(":/vectors/logs_dock_active_light.svg") + else: + self.log_dock_control.load(":/vectors/logs_dock_inactive_light.svg") + + def update_docking_icons(self, input_is_active=None, log_is_active=None, output_is_active=None): + + if(input_is_active is not None): + self.input_dock_active = input_is_active + # Update and save control state + self.input_dock_active = input_is_active + if self.input_dock_active: + self.input_dock_control.load(":/vectors/input_dock_active_light.svg") + else: + self.input_dock_control.load(":/vectors/input_dock_inactive_light.svg") + + # Update output dock icon + if(output_is_active is not None): + # Update and save control state + self.output_dock_active = output_is_active + if self.output_dock_active: + self.output_dock_control.load(":/vectors/output_dock_active_light.svg") + else: + self.output_dock_control.load(":/vectors/output_dock_inactive_light.svg") + + # Update log dock icon + if(log_is_active is not None): + self.log_dock_active = log_is_active + # Update and save control state + self.logs_dock_active = log_is_active + if self.log_dock_active: + self.log_dock_control.load(":/vectors/logs_dock_active_light.svg") + else: + self.log_dock_control.load(":/vectors/logs_dock_inactive_light.svg") + + def toggle_animate(self, show: bool, dock: str = 'output', on_finished=None): + sizes = self.splitter.sizes() + n = self.splitter.count() + if dock == 'input': + dock_index = 0 + + elif dock == 'output': + dock_index = n - 1 + elif dock == 'log': + self.logs_dock.setVisible(show) + if on_finished: + on_finished() + return + else: + print(f"[Error] Invalid dock: {dock}") + return + + dock_widget = self.splitter.widget(dock_index) + if show: + dock_widget.show() + + self.splitter.setMinimumWidth(0) + self.splitter.setCollapsible(dock_index, True) + for i in range(n): + self.splitter.widget(i).setMinimumWidth(0) + self.splitter.widget(i).setMaximumWidth(16777215) + + target_sizes = sizes[:] + total_width = self.width() - self.splitter.contentsMargins().left() - self.splitter.contentsMargins().right() + input_dock = self.splitter.widget(0) + output_dock = self.splitter.widget(n - 1) + + if dock == 'input': + if show: + target_sizes[0] = input_dock.sizeHint().width() + self.input_dock_label.setVisible(False) + else: + target_sizes[0] = 0 + self.input_dock_label.setVisible(True) + target_sizes[2] = sizes[2] + remaining_width = total_width - target_sizes[0] - target_sizes[2] + target_sizes[1] = max(0, remaining_width) + else: + if show: + target_sizes[2] = output_dock.sizeHint().width() + self.output_dock_label.setVisible(False) + else: + target_sizes[2] = 0 + self.output_dock_label.setVisible(True) + target_sizes[0] = sizes[0] + remaining_width = total_width - target_sizes[0] - target_sizes[2] + target_sizes[1] = max(0, remaining_width) + + if sizes == target_sizes: + if not show: + dock_widget.hide() + if on_finished: + on_finished() + return + + def after_anim(): + self.finalize_dock_toggle(show, dock_widget, target_sizes) + if on_finished: + on_finished() + + # User requested "one step animation" with "no delay" + self.animate_splitter_sizes( + self.splitter, + sizes, + target_sizes, + duration=0, + on_finished=after_anim + ) + + def animate_splitter_sizes(self, splitter, start_sizes, end_sizes, duration, on_finished=None): + if duration <= 0: + # Instant update + splitter.setSizes(end_sizes) + splitter.refresh() + if splitter.parentWidget() and splitter.parentWidget().layout(): + splitter.parentWidget().layout().activate() + splitter.update() + if splitter.parentWidget(): + splitter.parentWidget().update() + self.update() + for i in range(splitter.count()): + widget = splitter.widget(i) + if widget: + widget.update() + + if on_finished: + on_finished() + return + + # Target 60 FPS -> ~16ms interval + interval = 16 + steps = max(1, duration // interval) + + current_step = 0 + + def ease_out_quad(t): + return t * (2 - t) + + def update_step(): + nonlocal current_step + if current_step <= steps: + progress = current_step / steps + # Apply easing + eased_progress = ease_out_quad(progress) + + sizes = [ + int(start + (end - start) * eased_progress) + for start, end in zip(start_sizes, end_sizes) + ] + + splitter.setSizes(sizes) + splitter.refresh() + if splitter.parentWidget() and splitter.parentWidget().layout(): + splitter.parentWidget().layout().activate() + splitter.update() + if splitter.parentWidget(): + splitter.parentWidget().update() + self.update() + for i in range(splitter.count()): + widget = splitter.widget(i) + if widget: + widget.update() + + current_step += 1 + else: + timer.stop() + if on_finished: + on_finished() + + timer = QTimer(self) + timer.timeout.connect(update_step) + timer.start(interval) + self._splitter_anim = timer + + def finalize_dock_toggle(self, show, dock_widget, target_sizes): + self.splitter.setSizes(target_sizes) + if not show: + dock_widget.hide() + self.splitter.refresh() + self.splitter.parentWidget().layout().activate() + self.splitter.update() + self.splitter.parentWidget().update() + self.update() + for i in range(self.splitter.count()): + self.splitter.widget(i).update() + + #---------------------------------Docking-Icons-Functionality-END---------------------------------------------- + + def resizeEvent(self, event): + + """Override resizeEvent with safety check.""" + # Check if being deleted + if not self.isVisible() or self.signalsBlocked(): + return + + # Check if splitter exists and has children + try: + if not hasattr(self, 'splitter') or self.splitter is None: + return + if self.splitter.count() < 3: + return + + if self.input_dock.isVisible(): + input_dock_width = self.input_dock.sizeHint().width() + else: + input_dock_width = 0 + + if self.output_dock.isVisible(): + output_dock_width = self.output_dock.sizeHint().width() + else: + output_dock_width = 0 + total_width = self.width() - self.splitter.contentsMargins().left() - self.splitter.contentsMargins().right() + self.splitter.setMinimumWidth(0) + self.splitter.setCollapsible(0, True) + self.splitter.setCollapsible(1, True) + self.splitter.setCollapsible(2, True) + for i in range(self.splitter.count()): + self.splitter.widget(i).setMinimumWidth(0) + self.splitter.widget(i).setMaximumWidth(16777215) + target_sizes = [0] * self.splitter.count() + target_sizes[0] = input_dock_width + target_sizes[2] = output_dock_width + remaining_width = total_width - input_dock_width - output_dock_width + target_sizes[1] = max(0, remaining_width) + self.splitter.setSizes(target_sizes) + self.splitter.refresh() + self.body_widget.layout().activate() + self.splitter.update() + super().resizeEvent(event) + + except (IndexError, RuntimeError, AttributeError): + # Being deleted, ignore + return + + def create_menu_bar_items(self): + # File Menus + file_menu = self.menu_bar.addMenu("File") + + load_input_action = QAction("Load Input", self) + load_input_action.setShortcut(QKeySequence("Ctrl+L")) + file_menu.addAction(load_input_action) + + file_menu.addSeparator() + + save_input_action = QAction("Save Input", self) + save_input_action.setShortcut(QKeySequence("Ctrl+S")) + file_menu.addAction(save_input_action) + + save_log_action = QAction("Save Log Messages", self) + save_log_action.setShortcut(QKeySequence("Alt+M")) + file_menu.addAction(save_log_action) + + create_report_action = QAction("Create Design Report", self) + create_report_action.setShortcut(QKeySequence("Alt+C")) + file_menu.addAction(create_report_action) + + file_menu.addSeparator() + + save_3d_action = QAction("Save 3D Model", self) + save_3d_action.setShortcut(QKeySequence("Alt+3")) + file_menu.addAction(save_3d_action) + + save_cad_action = QAction("Save CAD Image", self) + save_cad_action.setShortcut(QKeySequence("Alt+I")) + file_menu.addAction(save_cad_action) + + file_menu.addSeparator() + + quit_action = QAction("Quit", self) + quit_action.setShortcut(QKeySequence("Shift+Q")) + file_menu.addAction(quit_action) + + # Edit Menus + edit_menu = self.menu_bar.addMenu("Edit") + + design_prefs_action = QAction("Additional Inputs", self) + design_prefs_action.setShortcut(QKeySequence("Alt+P")) + edit_menu.addAction(design_prefs_action) + + graphics_menu = self.menu_bar.addMenu("Graphics") + zoom_in_action = QAction("Zoom In", self) + zoom_in_action.setShortcut(QKeySequence("Ctrl+I")) + graphics_menu.addAction(zoom_in_action) + + zoom_out_action = QAction("Zoom Out", self) + zoom_out_action.setShortcut(QKeySequence("Ctrl+O")) + graphics_menu.addAction(zoom_out_action) + + pan_action = QAction("Pan", self) + pan_action.setShortcut(QKeySequence("Ctrl+P")) + graphics_menu.addAction(pan_action) + + rotate_3d_action = QAction("Rotate 3D Model", self) + rotate_3d_action.setShortcut(QKeySequence("Ctrl+R")) + graphics_menu.addAction(rotate_3d_action) + + graphics_menu.addSeparator() + + front_view_action = QAction("Show Front View", self) + front_view_action.setShortcut(QKeySequence("Alt+Shift+F")) + graphics_menu.addAction(front_view_action) + + top_view_action = QAction("Show Top View", self) + top_view_action.setShortcut(QKeySequence("Alt+Shift+T")) + graphics_menu.addAction(top_view_action) + + side_view_action = QAction("Show Side View", self) + side_view_action.setShortcut(QKeySequence("Alt+Shift+S")) + graphics_menu.addAction(side_view_action) + + # Database Menu + database_menu = self.menu_bar.addMenu("Database") + + input_csv_action = QAction("Save Inputs (.csv)", self) + database_menu.addAction(input_csv_action) + + output_csv_action = QAction("Save Outputs (.csv)", self) + database_menu.addAction(output_csv_action) + + input_osi_action = QAction("Save Inputs (.osi)", self) + database_menu.addAction(input_osi_action) + + download_database_menu = database_menu.addMenu("Download Database") + + download_column_action = QAction("Column", self) + download_database_menu.addAction(download_column_action) + + download_bolt_action = QAction("Beam", self) + download_database_menu.addAction(download_bolt_action) + + download_weld_action = QAction("Channel", self) + download_database_menu.addAction(download_weld_action) + + download_angle_action = QAction("Angle", self) + download_database_menu.addAction(download_angle_action) + + database_menu.addSeparator() + + reset_action = QAction("Reset", self) + reset_action.setShortcut(QKeySequence("Alt+R")) + database_menu.addAction(reset_action) + + # Help Menu + help_menu = self.menu_bar.addMenu("Help") + + video_tutorials_action = QAction("Video Tutorials", self) + help_menu.addAction(video_tutorials_action) + + design_examples_action = QAction("Design Examples", self) + help_menu.addAction(design_examples_action) + + help_menu.addSeparator() + + ask_question_action = QAction("Ask Us a Question", self) + help_menu.addAction(ask_question_action) + + about_osdag_action = QAction("About Osdag", self) + help_menu.addAction(about_osdag_action) + + help_menu.addSeparator() + + check_update_action = QAction("Check For Update", self) + help_menu.addAction(check_update_action) + + +class InputDockIndicator(QWidget): + def __init__(self, parent): + super().__init__(parent) + # Ensures automatic deletion when closed + self.setAttribute(Qt.WA_DeleteOnClose, True) + self.parent = parent + self.setObjectName("input_dock_indicator") + self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) # Fixed width, expanding height + + input_layout = QHBoxLayout(self) + input_layout.setContentsMargins(6,0,0,0) + input_layout.setSpacing(0) + + self.input_label = QSvgWidget(":/vectors/inputs_label_light.svg") + input_layout.addWidget(self.input_label) + self.input_label.setFixedWidth(32) + + self.toggle_strip = QWidget() + self.toggle_strip.setObjectName("toggle_strip") + self.toggle_strip.setFixedWidth(6) # Always visible + self.toggle_strip.setStyleSheet("background-color: #90AF13;") + toggle_layout = QVBoxLayout(self.toggle_strip) + toggle_layout.setContentsMargins(0, 0, 0, 0) + toggle_layout.setSpacing(0) + toggle_layout.setAlignment(Qt.AlignVCenter | Qt.AlignRight) # Align to right for input dock + + self.toggle_btn = QPushButton("❯") # Right-pointing chevron for input dock + self.toggle_btn.setFixedSize(6, 60) + self.toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.toggle_btn.clicked.connect(self.parent.input_dock_toggle) + self.toggle_btn.setToolTip("Show input panel") + self.toggle_btn.setObjectName("toggle_strip_button") + self.toggle_btn.setStyleSheet(""" + QPushButton { + background-color: #6c8408; + color: white; + font-size: 12px; + font-weight: bold; + padding: 0px; + border: none; + } + QPushButton:hover { + background-color: #5e7407; + } + """) + toggle_layout.addStretch() + toggle_layout.addWidget(self.toggle_btn) + toggle_layout.addStretch() + input_layout.addWidget(self.toggle_strip) + +class OutputDockIndicator(QWidget): + def __init__(self, parent): + super().__init__(parent) + # Ensures automatic deletion when closed + self.setAttribute(Qt.WA_DeleteOnClose, True) + self.parent = parent + self.setObjectName("output_dock_indicator") + self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) # Fixed width, expanding height + + output_layout = QHBoxLayout(self) + output_layout.setContentsMargins(0,0,0,0) + output_layout.setSpacing(0) + + self.toggle_strip = QWidget() + self.toggle_strip.setFixedWidth(6) # Always visible + self.toggle_strip.setObjectName("toggle_strip") + self.toggle_strip.setStyleSheet("background-color: #90AF13;") + toggle_layout = QVBoxLayout(self.toggle_strip) + toggle_layout.setContentsMargins(0, 0, 0, 0) + toggle_layout.setSpacing(0) + toggle_layout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) + + self.toggle_btn = QPushButton("❮") # Show state initially + self.toggle_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.toggle_btn.setFixedSize(6, 60) + self.toggle_btn.clicked.connect(self.parent.output_dock_toggle) + self.toggle_btn.setToolTip("Show panel") + self.toggle_btn.setObjectName("toggle_strip_button") + self.toggle_btn.setStyleSheet(""" + QPushButton { + background-color: #6c8408; + color: white; + font-size: 12px; + font-weight: bold; + padding: 0px; + border: none; + } + QPushButton:hover { + background-color: #5e7407; + } + """) + toggle_layout.addStretch() + toggle_layout.addWidget(self.toggle_btn) + toggle_layout.addStretch() + output_layout.addWidget(self.toggle_strip) + + self.output_label = QSvgWidget(":/vectors/outputs_label_light.svg") + output_layout.addWidget(self.output_label) + self.output_label.setFixedWidth(28) + diff --git a/src/osdagbridge/desktop/ui/utils/custom_buttons.py b/src/osdagbridge/desktop/ui/utils/custom_buttons.py new file mode 100644 index 00000000..6588616c --- /dev/null +++ b/src/osdagbridge/desktop/ui/utils/custom_buttons.py @@ -0,0 +1,71 @@ +""" +Custom button widgets for Osdag GUI. +Includes menu and action buttons with custom styles. +""" +from PySide6.QtWidgets import ( + QWidget, QPushButton, QVBoxLayout, QHBoxLayout, QApplication, QGridLayout, + QLabel, QMainWindow, QSizePolicy, QFrame +) +from PySide6.QtSvgWidgets import QSvgWidget +from PySide6.QtCore import Qt, Signal, QSize, QEvent, QRect, QPropertyAnimation, QEasingCurve +from PySide6.QtGui import QFont, QIcon, QPainter + +class DockCustomButton(QPushButton): + def __init__(self, text: str, icon_path: str, parent=None): + super().__init__(parent) + self.setCursor(Qt.PointingHandCursor) + self.setObjectName("dock_custom_button") + self.setStyleSheet(""" + QPushButton { + background-color: #90AF13; + color: white; + border: none; + border-radius: 4px; + padding: 10px; + font-size: 11px; + font-weight: bold; + } + QPushButton:hover { + background-color: #7a9a12; + } + """) + + # Layout for icons and text + layout = QHBoxLayout(self) + layout.setContentsMargins(10, 0, 10, 0) + layout.setSpacing(0) + + # Left icon + left_icon = QSvgWidget() + left_icon.load(icon_path) + left_icon.setFixedSize(18, 18) + left_icon.setObjectName("button_icon") + left_icon.setStyleSheet(""" + QSvgWidget { + background: transparent; + } + """) + layout.addWidget(left_icon) + + # Center text + text_label = QLabel(text) + text_label.setAlignment(Qt.AlignCenter) + text_label.setObjectName("button_label") + text_label.setStyleSheet(""" + QLabel { + background: transparent; + color: white; + } + """) + layout.addWidget(text_label) + + layout.setAlignment(Qt.AlignVCenter) + self.setLayout(layout) + + # Calculate minimum width to prevent overlap + text_width = text_label.sizeHint().width() + icon_width = 18 + margins = layout.contentsMargins().left() + layout.contentsMargins().right() + padding = 20 + min_width = text_width + icon_width + margins + padding + self.setMinimumWidth(min_width) \ No newline at end of file diff --git a/src/osdagbridge/desktop/ui/utils/custom_titlebar.py b/src/osdagbridge/desktop/ui/utils/custom_titlebar.py new file mode 100644 index 00000000..be46a2e4 --- /dev/null +++ b/src/osdagbridge/desktop/ui/utils/custom_titlebar.py @@ -0,0 +1,168 @@ +from PySide6.QtWidgets import QWidget, QLabel, QToolButton, QHBoxLayout, QSizePolicy, QVBoxLayout +from PySide6.QtCore import Qt, QPoint, QEvent +from PySide6.QtGui import QMouseEvent, QFont + +class CustomTitleBar(QWidget): + def __init__(self, max_res_btn: bool = False, min_res_btn:bool = False, parent=None): + super().__init__(parent) + # Ensures automatic deletion when closed + self.setAttribute(Qt.WA_DeleteOnClose, True) + self._drag_pos = QPoint() + self.setObjectName("CustomTitleBar") + self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + self.setFixedHeight(32) # Set consistent height + self.setAttribute(Qt.WA_StyledBackground, True) + + # Add Osdag logo icon to the title bar + from PySide6.QtSvgWidgets import QSvgWidget + self.logo_label = QSvgWidget(":/vectors/Osdag_logo.svg", self) + self.logo_label.setObjectName("LogoLabel") + self.logo_label.setFixedSize(20, 20) + + # Title label + self.title_label = QLabel("Osdag", self) + self.title_label.setObjectName("TitleLabel") + self.title_label.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) + + # Set font for title + title_font = QFont() + title_font.setPointSize(9) + title_font.setWeight(QFont.Weight.Medium) + self.title_label.setFont(title_font) + + # Minimize button (optional) + self.btn_minimize = None + if min_res_btn: + self.btn_minimize = QToolButton(self) + self.btn_minimize.setObjectName("MinimizeButton") + self.btn_minimize.setToolTip("Minimize") + self.btn_minimize.setText("–") + self.btn_minimize.setFixedSize(46, 32) + self.btn_minimize.clicked.connect(self._minimize_parent) + + # Maximize/Restore button (optional) + self.btn_max_restore = None + if max_res_btn: + self.btn_max_restore = QToolButton(self) + self.btn_max_restore.setObjectName("MaxRestoreButton") + self.btn_max_restore.setToolTip("Maximize") + self.btn_max_restore.setText("□") + self.btn_max_restore.setFixedSize(46, 32) + self.btn_max_restore.clicked.connect(self._toggle_max_restore) + + # Close button + self.btn_close = QToolButton(self) + self.btn_close.setObjectName("CloseButton") + self.btn_close.setToolTip("Close") + self.btn_close.setText("✕") # Better multiplication symbol + self.btn_close.setFixedSize(46, 32) + self.btn_close.clicked.connect(self._close_parent) + + # Title bar layout + outer_layout = QVBoxLayout(self) + outer_layout.setContentsMargins(0, 0, 0, 0) + outer_layout.setSpacing(0) + + row_widget = QWidget(self) + row_layout = QHBoxLayout(row_widget) + row_layout.setContentsMargins(8, 0, 0, 0) + row_layout.setSpacing(8) + row_layout.addWidget(self.logo_label, 0) + row_layout.addWidget(self.title_label, 1) + if self.btn_minimize is not None: + row_layout.addWidget(self.btn_minimize, 0) + if self.btn_max_restore is not None: + row_layout.addWidget(self.btn_max_restore, 0) + row_layout.addWidget(self.btn_close, 0) + outer_layout.addWidget(row_widget) + + self.bottom_line = QWidget(self) + self.bottom_line.setObjectName("BottomLine") + self.bottom_line.setFixedHeight(1) + outer_layout.addWidget(self.bottom_line) + + # Keep the maximize/restore button state in sync with the window state + if self.btn_max_restore is not None and self.parent() is not None: + self.parent().installEventFilter(self) + self._update_max_restore_icon() + + def setTitle(self, title): + """Set the title displayed in the title bar.""" + self.title_label.setText(title) + + def _close_parent(self): + """Close the parent widget.""" + if self.parent(): + self.parent().close() + + def _minimize_parent(self): + """Minimize the parent widget.""" + if self.parent(): + self.parent().showMinimized() + + def _toggle_max_restore(self): + """Toggle between maximizing and restoring the parent window.""" + window = self.parent() + if not window: + return + if window.isMaximized(): + window.showNormal() + else: + window.showMaximized() + self._update_max_restore_icon() + + def _update_max_restore_icon(self): + """Update the icon/text and tooltip of the maximize/restore button based on window state.""" + if self.btn_max_restore is None: + return + window = self.parent() + if not window: + return + if window.isMaximized(): + self.btn_max_restore.setText("❐") # Restore + self.btn_max_restore.setToolTip("Restore") + else: + self.btn_max_restore.setText("□") # Maximize + self.btn_max_restore.setToolTip("Maximize") + + def eventFilter(self, obj, event): + # Update button when window state changes (e.g., via system controls or double-click) + if obj is self.parent() and event.type() == QEvent.WindowStateChange: + self._update_max_restore_icon() + return super().eventFilter(obj, event) + + def mousePressEvent(self, event: QMouseEvent): + """Handle mouse press for dragging.""" + if event.button() == Qt.LeftButton: + if self.parent() and self.parent().isWindow(): + self._drag_pos = event.globalPosition().toPoint() - self.parent().frameGeometry().topLeft() + event.accept() + + def mouseMoveEvent(self, event: QMouseEvent): + """Handle mouse move for dragging.""" + if (event.buttons() & Qt.LeftButton and + not self._drag_pos.isNull() and + self.parent() and + self.parent().isWindow()): + self.parent().move(event.globalPosition().toPoint() - self._drag_pos) + event.accept() + + def mouseReleaseEvent(self, event: QMouseEvent): + """Reset drag position on mouse release.""" + if event.button() == Qt.LeftButton: + self._drag_pos = QPoint() + event.accept() + + def mouseDoubleClickEvent(self, event: QMouseEvent): + """Handle double-click to maximize/restore window.""" + if event.button() == Qt.LeftButton and self.parent() and self.parent().isWindow(): + if self.parent().isMaximized(): + self.parent().showNormal() + else: + self.parent().showMaximized() + # Keep button state in sync + if self.btn_max_restore is not None: + self._update_max_restore_icon() + event.accept() + else: + super().mouseDoubleClickEvent(event) diff --git a/src/osdagbridge/desktop/ui/utils/rolled_section_preview.py b/src/osdagbridge/desktop/ui/utils/rolled_section_preview.py new file mode 100644 index 00000000..b580abaa --- /dev/null +++ b/src/osdagbridge/desktop/ui/utils/rolled_section_preview.py @@ -0,0 +1,756 @@ +"""Interactive beam preview widget with CAD-style annotations.""" + +from __future__ import annotations + +import math +from typing import Dict, Optional + +from PySide6.QtCore import QPointF, QRectF, Qt +from PySide6.QtGui import QColor, QFont, QPainter, QPaintEvent, QPainterPath, QPen, QTextDocument +from PySide6.QtWidgets import QSizePolicy, QWidget + +from osdagbridge.core.bridge_components.super_structure.girder.properties import BeamSection + + +OSDAG_BRAND_GREEN = QColor("#90AF13") +OSDAG_FONT_FAMILY = "Ubuntu Sans" + + +class RolledSectionPreview(QWidget): + """Render a rolled or welded section with CAD-style dimension annotations.""" + + def __init__(self, parent: Optional[QWidget] = None) -> None: + super().__init__(parent) + self._section: Optional[BeamSection] = None + self._dimensions: Dict[str, float] = {} + + self._outline_color = QColor("#1b1b1b") + self._outline_width = 3.0 + self._brand_color = QColor(OSDAG_BRAND_GREEN) + self._dimension_color = QColor(OSDAG_BRAND_GREEN) + self._dimension_keys = ("tfw", "tft", "bfw", "bft", "d", "wt") + self._dimension_palette = {key: QColor(OSDAG_BRAND_GREEN) for key in self._dimension_keys} + self._label_bg = QColor(255, 255, 255, 230) + self._text_color = QColor("#0f0f0f") + self._brand_font_family = OSDAG_FONT_FAMILY + self._show_welds = False + + self._outer_margin = 16 + self._annotation_margin_top = 36 + self._annotation_margin_bottom = 28 + self._annotation_margin_left = 52 + self._annotation_margin_right = 74 + self._dim_gap = 12 + self._arrow_size = 9 + + # Minimum radii keep rolled sections visibly curved even when the + # catalogue omits R1/R2. + self._min_root_radius_px = 8.0 + self._min_toe_radius_px = 4.0 + + self.setMinimumSize(360, 260) + self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + + # ------------------------------------------------------------------ + # Public API + # ------------------------------------------------------------------ + def set_section(self, section: Optional[BeamSection]) -> None: + """Update the preview to show the supplied ``BeamSection`` (assumed rolled).""" + + self._section = section + if section is None: + self._dimensions = {} + else: + self._dimensions = { + "depth": float(section.depth_mm), + "top_flange_width": float(section.flange_width_mm), + "bottom_flange_width": float(section.flange_width_mm), + "web_thickness": float(section.web_thickness_mm), + "top_flange_thickness": float(section.flange_thickness_mm), + "bottom_flange_thickness": float(section.flange_thickness_mm), + "root_radius_mm": float(section.root_radius_r1_mm or 0.0), + "toe_radius_mm": float(section.root_radius_r2_mm or 0.0), + } + # Rolled sections do not show weld symbols. + self._show_welds = False + self.update() + + def set_dimensions( + self, + *, + depth_mm: float, + flange_width_mm: float, + web_thickness_mm: float, + flange_thickness_mm: float, + bottom_flange_width_mm: Optional[float] = None, + bottom_flange_thickness_mm: Optional[float] = None, + show_welds: bool = False, + ) -> None: + """Feed custom dimensions directly (e.g., for welded sections).""" + + self._section = None + self._dimensions = { + "depth": float(depth_mm), + "top_flange_width": float(flange_width_mm), + "bottom_flange_width": float(bottom_flange_width_mm or flange_width_mm), + "web_thickness": float(web_thickness_mm), + "top_flange_thickness": float(flange_thickness_mm), + "bottom_flange_thickness": float(bottom_flange_thickness_mm or flange_thickness_mm), + # Welded sections have no root/toe radii. + "root_radius_mm": 0.0, + "toe_radius_mm": 0.0, + } + self._show_welds = show_welds + self.update() + + def clear(self) -> None: + """Reset the preview to an empty placeholder.""" + + self._section = None + self._dimensions = {} + self._show_welds = False + self.update() + + # ------------------------------------------------------------------ + # QWidget overrides + # ------------------------------------------------------------------ + def paintEvent(self, event: QPaintEvent) -> None: # noqa: D401 - Qt override + painter = QPainter(self) + painter.setRenderHint(QPainter.Antialiasing, True) + painter.fillRect(self.rect(), self.palette().window()) + + if not self._dimensions: + self._draw_placeholder(painter) + return + + dims = self._dimensions + depth = max(dims.get("depth", 0.0), 1.0) + top_width = max(dims.get("top_flange_width", 0.0), 1.0) + bottom_width = max(dims.get("bottom_flange_width", top_width), 1.0) + web_thickness = max(dims.get("web_thickness", 0.0), 0.5) + top_thickness = max(dims.get("top_flange_thickness", 0.0), 0.5) + bottom_thickness = max(dims.get("bottom_flange_thickness", top_thickness), 0.5) + + usable_rect = self.rect().adjusted( + self._outer_margin + 20, # extra left space for labels + self._outer_margin, + -self._outer_margin, + -self._outer_margin, + ) + beam_rect = QRectF( + usable_rect.left() + self._annotation_margin_left, + usable_rect.top() + self._annotation_margin_top, + max(20.0, usable_rect.width() - self._annotation_margin_left - self._annotation_margin_right), + max(20.0, usable_rect.height() - self._annotation_margin_top - self._annotation_margin_bottom), + ) + + max_width = max(top_width, bottom_width) + scale_w = beam_rect.width() / max_width + scale_h = beam_rect.height() / depth + scale = min(scale_w, scale_h) * 0.92 + + beam_height = depth * scale + top_height = min(top_thickness * scale, beam_height * 0.4) + bottom_height = min(bottom_thickness * scale, beam_height * 0.4) + web_height = max(beam_height - top_height - bottom_height, scale * 2.0) + + center_x = beam_rect.center().x() + top_y = beam_rect.center().y() - (top_height + web_height + bottom_height) / 2.0 + + top_flange = QRectF( + center_x - (top_width * scale) / 2.0, + top_y, + top_width * scale, + top_height, + ) + web = QRectF( + center_x - (web_thickness * scale) / 2.0, + top_flange.bottom(), + max(1.0, web_thickness * scale), + web_height, + ) + bottom_flange = QRectF( + center_x - (bottom_width * scale) / 2.0, + web.bottom(), + bottom_width * scale, + bottom_height, + ) + + root_radius_px = float(dims.get("root_radius_mm", 0.0)) * scale + toe_radius_px = float(dims.get("toe_radius_mm", 0.0)) * scale + + section_path = self._build_section_path( + top_flange, + web, + bottom_flange, + root_radius_px, + toe_radius_px, + ) + + painter.save() + outline_pen = QPen(self._outline_color, self._outline_width) + outline_pen.setJoinStyle(Qt.MiterJoin) + painter.setPen(outline_pen) + painter.setBrush(QColor("#fefefe")) + if section_path is not None: + painter.drawPath(section_path) + else: + painter.drawRect(top_flange) + painter.drawRect(web) + painter.drawRect(bottom_flange) + painter.restore() + + if self._show_welds: + self._draw_welds(painter, top_flange, web, bottom_flange) + + font = QFont(self.font()) + font.setFamily(self._brand_font_family) + font.setPointSizeF(max(9.0, font.pointSizeF())) + painter.setFont(font) + + # --- Top flange width dimension --- + tfw_color = self._set_dimension_pen(painter, "tfw") + width_dim_y = self._snap_coordinate(top_flange.top() - self._dim_gap) + left_extension_end = QPointF(self._snap_coordinate(top_flange.left()), width_dim_y) + right_extension_end = QPointF(self._snap_coordinate(top_flange.right()), width_dim_y) + painter.drawLine(QPointF(left_extension_end.x(), top_flange.top()), left_extension_end) + painter.drawLine(QPointF(right_extension_end.x(), top_flange.top()), right_extension_end) + self._draw_dimension_line( + painter, + left_extension_end, + right_extension_end, + tfw_color, + ) + self._draw_label( + painter, + self._format_label_markup("tfw", top_width), + QPointF(top_flange.center().x(), width_dim_y - 6), + Qt.AlignHCenter | Qt.AlignBottom, + with_background=False, + color=tfw_color, + ) + + # --- Top flange thickness dimension --- + tft_color = self._set_dimension_pen(painter, "tft") + self._draw_vertical_thickness_dimension( + painter, + top_flange.left(), + top_flange.top(), + top_flange.bottom(), + top_thickness, + tft_color, + label_symbol="tft", + label_align=Qt.AlignRight | Qt.AlignVCenter, + ) + + # --- Bottom flange width dimension --- + bfw_color = self._set_dimension_pen(painter, "bfw") + bottom_width_dim_y = self._snap_coordinate(bottom_flange.bottom() + self._dim_gap) + bottom_left_extension = QPointF(self._snap_coordinate(bottom_flange.left()), bottom_width_dim_y) + bottom_right_extension = QPointF(self._snap_coordinate(bottom_flange.right()), bottom_width_dim_y) + painter.drawLine(QPointF(bottom_left_extension.x(), bottom_flange.bottom()), bottom_left_extension) + painter.drawLine(QPointF(bottom_right_extension.x(), bottom_flange.bottom()), bottom_right_extension) + self._draw_dimension_line( + painter, + bottom_left_extension, + bottom_right_extension, + bfw_color, + ) + self._draw_label( + painter, + self._format_label_markup("bfw", bottom_width), + QPointF(bottom_flange.center().x(), bottom_width_dim_y + 6), + Qt.AlignHCenter | Qt.AlignTop, + with_background=False, + color=bfw_color, + ) + + # --- Bottom flange thickness dimension --- + bft_color = self._set_dimension_pen(painter, "bft") + self._draw_vertical_thickness_dimension( + painter, + bottom_flange.left(), + bottom_flange.top(), + bottom_flange.bottom(), + bottom_thickness, + bft_color, + label_symbol="bft", + label_align=Qt.AlignRight | Qt.AlignVCenter, + ) + + # --- Overall depth dimension --- + depth_color = self._set_dimension_pen(painter, "d") + anchor_x = self._snap_coordinate(bottom_flange.right()) + depth_dim_x = self._snap_coordinate(anchor_x + self._dim_gap) + top_depth_extension = QPointF(depth_dim_x, self._snap_coordinate(top_flange.top())) + bottom_depth_extension = QPointF(depth_dim_x, self._snap_coordinate(bottom_flange.bottom())) + painter.drawLine(QPointF(anchor_x, top_depth_extension.y()), top_depth_extension) + painter.drawLine(QPointF(anchor_x, bottom_depth_extension.y()), bottom_depth_extension) + self._draw_dimension_line( + painter, + top_depth_extension, + bottom_depth_extension, + depth_color, + ) + self._draw_label( + painter, + self._format_label_markup("d", depth), + QPointF(depth_dim_x + 10, (top_flange.top() + bottom_flange.bottom()) / 2.0), + Qt.AlignLeft | Qt.AlignVCenter, + with_background=False, + color=depth_color, + ) + + # --- Web thickness dimension --- + wt_color = self._set_dimension_pen(painter, "wt") + self._draw_web_thickness_dimension( + painter, + web.left(), + web.right(), + web.center().y(), + web_thickness, + wt_color, + label_symbol="wt", + ) + + + # ------------------------------------------------------------------ + # Drawing helpers + # ------------------------------------------------------------------ + def _build_section_path( + self, + top_flange: QRectF, + web: QRectF, + bottom_flange: QRectF, + root_radius: float, + toe_radius: float, + ) -> Optional[QPainterPath]: + """ + Builds the section path. + - For rolled sections: SHARP outer corners, CURVED inner corners/roots. + - For welded sections: ALL corners are SHARP (radii are 0). + """ + if min(top_flange.width(), bottom_flange.width(), web.width()) <= 0: + return None + + tf_left, tf_right = top_flange.left(), top_flange.right() + tf_top, tf_bottom = top_flange.top(), top_flange.bottom() + bf_left, bf_right = bottom_flange.left(), bottom_flange.right() + bf_top, bf_bottom = bottom_flange.top(), bottom_flange.bottom() + web_left, web_right = web.left(), web.right() + + # Determine effective radii. + # For welded sections, these will be 0.0. + # For rolled sections, minimum visual values are enforced if DB values are missing. + top_root = self._effective_root_radius_px(root_radius, top_flange, web) + bottom_root = self._effective_root_radius_px(root_radius, bottom_flange, web) + top_toe = self._effective_toe_radius_px(toe_radius, top_flange) + bottom_toe = self._effective_toe_radius_px(toe_radius, bottom_flange) + + path = QPainterPath() + + # --- TOP FLANGE --- + + # 1. Start at Top-Left Corner (Sharp) + path.moveTo(tf_left, tf_top) + + # 2. Top Edge -> Top-Right Corner (Sharp) + path.lineTo(tf_right, tf_top) + + # 3. Top-Right Vertical Face -> Start of Toe Curve + path.lineTo(tf_right, tf_bottom - top_toe) + + # 4. Top-Right Inner Toe Curve (R2) + if top_toe > 0: + rect = QRectF(tf_right - 2*top_toe, tf_bottom - 2*top_toe, 2*top_toe, 2*top_toe) + path.arcTo(rect, 0, -90) + else: + path.lineTo(tf_right, tf_bottom) + + # 5. Underside -> Start of Root Curve (R1) + path.lineTo(web_right + top_root, tf_bottom) + + # 6. Top-Right Root Fillet (R1) + if top_root > 0: + rect = QRectF(web_right, tf_bottom, 2*top_root, 2*top_root) + path.arcTo(rect, 90, 90) + else: + path.lineTo(web_right, tf_bottom) + + # 7. Web Right Side -> Bottom Root + path.lineTo(web_right, bf_top - bottom_root) + + # 8. Bottom-Right Root Fillet (R1) + if bottom_root > 0: + rect = QRectF(web_right, bf_top - 2*bottom_root, 2*bottom_root, 2*bottom_root) + path.arcTo(rect, 180, 90) + else: + path.lineTo(web_right, bf_top) + + # 9. Bottom Flange Top Side -> Inner Toe + path.lineTo(bf_right - bottom_toe, bf_top) + + # 10. Bottom-Right Inner Toe Curve (R2) + if bottom_toe > 0: + rect = QRectF(bf_right - 2*bottom_toe, bf_top, 2*bottom_toe, 2*bottom_toe) + path.arcTo(rect, 90, -90) + else: + path.lineTo(bf_right, bf_top) + + # 11. Bottom-Right Vertical Face -> Bottom-Right Corner (Sharp) + path.lineTo(bf_right, bf_bottom) + + # 12. Bottom Edge -> Bottom-Left Corner (Sharp) + path.lineTo(bf_left, bf_bottom) + + # 13. Bottom-Left Vertical Face -> Inner Toe + path.lineTo(bf_left, bf_top + bottom_toe) + + # 14. Bottom-Left Inner Toe Curve (R2) + if bottom_toe > 0: + rect = QRectF(bf_left, bf_top, 2*bottom_toe, 2*bottom_toe) + path.arcTo(rect, 180, -90) + else: + path.lineTo(bf_left, bf_top) + + # 15. Top Side -> Root + path.lineTo(web_left - bottom_root, bf_top) + + # 16. Bottom-Left Root Fillet (R1) + if bottom_root > 0: + rect = QRectF(web_left - 2*bottom_root, bf_top - 2*bottom_root, 2*bottom_root, 2*bottom_root) + path.arcTo(rect, 270, 90) + else: + path.lineTo(web_left, bf_top) + + # 17. Web Left Side -> Top Root + path.lineTo(web_left, tf_bottom + top_root) + + # 18. Top-Left Root Fillet (R1) + if top_root > 0: + rect = QRectF(web_left - 2*top_root, tf_bottom, 2*top_root, 2*top_root) + path.arcTo(rect, 0, 90) + else: + path.lineTo(web_left, tf_bottom) + + # 19. Underside -> Inner Toe + path.lineTo(tf_left + top_toe, tf_bottom) + + # 20. Top-Left Inner Toe Curve (R2) + if top_toe > 0: + rect = QRectF(tf_left, tf_bottom - 2*top_toe, 2*top_toe, 2*top_toe) + path.arcTo(rect, 270, -90) + else: + path.lineTo(tf_left, tf_bottom) + + # 21. Left Face -> Back to Start (Sharp) + path.lineTo(tf_left, tf_top) + + path.closeSubpath() + return path + + def _snap_coordinate(self, value: float, *, precision: float = 0.5) -> float: + """Quantize coordinates to reduce anti-alias fuzz on shared anchors.""" + + if not precision or precision <= 0: + return value + return round(value / precision) * precision + + def _effective_toe_radius_px(self, requested: float, flange: QRectF) -> float: + # If this is a welded section, radii must be sharp. + if self._show_welds: + return 0.0 + + max_radius = max(0.0, min(flange.width() / 2.0, flange.height())) + if max_radius == 0.0: + return 0.0 + + # Enforce Minimum Visual Radius (e.g. 4px) if requested is 0/missing for rolled sections + val = max(requested, self._min_toe_radius_px) + return self._snap_coordinate(min(val, max_radius)) + + def _effective_root_radius_px(self, requested: float, flange: QRectF, web: QRectF) -> float: + # If this is a welded section, radii must be sharp. + if self._show_welds: + return 0.0 + + flange_overhang = (flange.width() - web.width()) / 2.0 + max_radius = max(0.0, min(flange_overhang, web.height() / 2.0)) + + if max_radius == 0.0: + return 0.0 + + # Enforce Minimum Visual Radius (e.g. 8px) if requested is 0/missing for rolled sections + val = max(requested, self._min_root_radius_px) + return self._snap_coordinate(min(val, max_radius)) + + def _draw_welds(self, painter: QPainter, top_flange: QRectF, web: QRectF, bottom_flange: QRectF) -> None: + painter.save() + painter.setRenderHint(QPainter.Antialiasing, True) + fill_color = QColor("#0f0f0f") + outline_pen = QPen(QColor("#0f0f0f"), 0.9) + outline_pen.setCosmetic(True) + painter.setBrush(fill_color) + painter.setPen(outline_pen) + + horizontal_leg = max(4.0, min(web.width() * 0.8, 24.0)) + top_vertical_leg = max(4.0, min(top_flange.height() * 0.9, 22.0)) + bottom_vertical_leg = max(4.0, min(bottom_flange.height() * 0.9, 22.0)) + + for sign in (-1, 1): + top_corner_x = web.left() if sign < 0 else web.right() + top_corner = QPointF(top_corner_x, top_flange.bottom()) + painter.drawPath( + self._build_fillet_path( + top_corner, + horizontal_leg, + top_vertical_leg, + horizontal_sign=sign, + vertical_sign=1.0, + ) + ) + + bottom_corner_x = web.left() if sign < 0 else web.right() + bottom_corner = QPointF(bottom_corner_x, bottom_flange.top()) + painter.drawPath( + self._build_fillet_path( + bottom_corner, + horizontal_leg, + bottom_vertical_leg, + horizontal_sign=sign, + vertical_sign=-1.0, + ) + ) + + painter.restore() + + def _build_fillet_path( + self, + corner: QPointF, + horizontal_leg: float, + vertical_leg: float, + *, + horizontal_sign: float, + vertical_sign: float, + ) -> QPainterPath: + leg_x = horizontal_leg * horizontal_sign + leg_y = vertical_leg * vertical_sign + path = QPainterPath(corner) + path.lineTo(QPointF(corner.x() + leg_x, corner.y())) + control = QPointF(corner.x() + leg_x * 0.55, corner.y() + leg_y * 0.55) + path.quadTo(control, QPointF(corner.x(), corner.y() + leg_y)) + path.closeSubpath() + return path + + def _draw_placeholder(self, painter: QPainter) -> None: + painter.save() + pen = QPen(QColor("#b7b7b7"), 1.2, Qt.DashLine) + pen.setCosmetic(True) + painter.setPen(pen) + painter.drawRect(self.rect().adjusted(12, 12, -12, -12)) + painter.setPen(QColor("#6f6f6f")) + font = QFont(self.font()) + font.setFamily(self._brand_font_family) + font.setPointSizeF(max(font.pointSizeF(), 10.0)) + painter.setFont(font) + painter.drawText(self.rect(), Qt.AlignCenter, "Select a section to preview") + painter.restore() + + def _set_dimension_pen(self, painter: QPainter, key: str) -> QColor: + color = self._dimension_palette.get(key, self._dimension_color) + pen = QPen(color, 1.6) + pen.setCosmetic(True) + pen.setCapStyle(Qt.FlatCap) + painter.setPen(pen) + return color + + def _draw_vertical_thickness_dimension( + self, + painter: QPainter, + flange_edge_x: float, + top_y: float, + bottom_y: float, + thickness: Optional[float], + color: QColor, + *, + label_symbol: str, + label_align: Qt.Alignment, + ) -> None: + extension = self._dim_gap * 0.9 + anchor_x = self._snap_coordinate(flange_edge_x) + dimension_x = self._snap_coordinate(anchor_x - extension) + snapped_top_y = self._snap_coordinate(top_y) + snapped_bottom_y = self._snap_coordinate(bottom_y) + top_extension = QPointF(dimension_x, snapped_top_y) + bottom_extension = QPointF(dimension_x, snapped_bottom_y) + + painter.drawLine(QPointF(anchor_x, snapped_top_y), top_extension) + painter.drawLine(QPointF(anchor_x, snapped_bottom_y), bottom_extension) + painter.drawLine(top_extension, bottom_extension) + self._draw_arrow_head(painter, top_extension, QPointF(0, -1), color) + self._draw_arrow_head(painter, bottom_extension, QPointF(0, 1), color) + + label_anchor = QPointF( + dimension_x - self._dim_gap * 0.4, + (snapped_top_y + snapped_bottom_y) / 2.0, + ) + self._draw_label( + painter, + self._format_label_markup(label_symbol, thickness), + label_anchor, + label_align, + with_background=False, + color=color, + ) + + def _draw_web_thickness_dimension( + self, + painter: QPainter, + left_x: float, + right_x: float, + mid_y: float, + thickness: Optional[float], + color: QColor, + *, + label_symbol: str, + ) -> None: + snapped_mid_y = self._snap_coordinate(mid_y) + left_point = QPointF(self._snap_coordinate(left_x), snapped_mid_y) + right_point = QPointF(self._snap_coordinate(right_x), snapped_mid_y) + painter.drawLine(left_point, right_point) + self._draw_arrow_head(painter, left_point, QPointF(-1, 0), color) + self._draw_arrow_head(painter, right_point, QPointF(1, 0), color) + + label_offset = self._dim_gap * 0.6 + label_anchor = QPointF(left_point.x() - label_offset, snapped_mid_y) + self._draw_label( + painter, + self._format_label_markup(label_symbol, thickness), + label_anchor, + Qt.AlignRight | Qt.AlignVCenter, + with_background=False, + color=color, + ) + + def _draw_dimension_line( + self, + painter: QPainter, + start: QPointF, + end: QPointF, + color: QColor, + *, + external: bool = False, + ) -> None: + direction = QPointF(end.x() - start.x(), end.y() - start.y()) + length = math.hypot(direction.x(), direction.y()) + if length == 0: + return + painter.drawLine(start, end) + self._draw_arrow_head(painter, start, direction, color) + self._draw_arrow_head(painter, end, QPointF(-direction.x(), -direction.y()), color) + + def _draw_arrow_head(self, painter: QPainter, tip: QPointF, direction: QPointF, color: QColor) -> None: + length = math.hypot(direction.x(), direction.y()) + if length == 0: + return + + unit = QPointF(direction.x() / length, direction.y() / length) + normal = QPointF(-unit.y(), unit.x()) + + arrow = self._arrow_size + + # --- Adjusted Geometry for Narrow/Tall Arrows --- + # 1.3 makes the arrow longer/taller (previously 0.9) + arrow_length = arrow * 1.3 + + # 0.25 makes the base narrower (previously 0.45) + # This creates a sharp, technical drafting look. + arrow_half_width = arrow * 0.25 + + base = tip + unit * arrow_length + left = base + normal * arrow_half_width + right = base - normal * arrow_half_width + + painter.save() + painter.setBrush(color) + painter.setPen(Qt.NoPen) + painter.drawPolygon([tip, left, right]) + painter.restore() + + def _draw_label( + self, + painter: QPainter, + text: str, + anchor: QPointF, + align: Qt.Alignment, + *, + with_background: bool = True, + color: Optional[QColor] = None, + ) -> None: + text_color = color or self._text_color + html_text = text if color is None else f'{text}' + + doc = QTextDocument() + doc.setDefaultFont(painter.font()) + doc.setHtml(html_text) + text_size = doc.size() + padding_x = 6 + padding_y = 4 + rect = QRectF(0, 0, text_size.width() + padding_x * 2, text_size.height() + padding_y * 2) + + if align & Qt.AlignLeft: + rect.moveLeft(anchor.x()) + elif align & Qt.AlignRight: + rect.moveRight(anchor.x()) + else: + rect.moveCenter(QPointF(anchor.x(), rect.center().y())) + + if align & Qt.AlignTop: + rect.moveTop(anchor.y()) + elif align & Qt.AlignBottom: + rect.moveBottom(anchor.y()) + else: + rect.moveCenter(QPointF(rect.center().x(), anchor.y())) + + content_rect = QRectF( + rect.left() + padding_x, + rect.top() + padding_y, + text_size.width(), + text_size.height(), + ) + + if with_background: + painter.save() + painter.setPen(Qt.NoPen) + painter.setBrush(self._label_bg) + painter.drawRoundedRect(rect, 4, 4) + painter.restore() + + painter.save() + painter.translate(content_rect.topLeft()) + doc.drawContents(painter) + painter.restore() + + def _format_label_markup(self, symbol: str, value: Optional[float] = None) -> str: + formatted_symbol = self._format_symbol_markup(symbol) + if value is None: + return formatted_symbol + return f"{formatted_symbol} = {self._format_mm(value)}" + + @staticmethod + def _format_symbol_markup(symbol: str) -> str: + clean = symbol.lower().strip() + if len(clean) <= 1: + return clean or symbol + return f"{clean[0]}{clean[1:]}" + + @staticmethod + def _color_to_hex(color: QColor) -> str: + return color.name(QColor.HexRgb) + + @staticmethod + def _format_mm(value: float) -> str: + rounded = round(value) + if abs(value - rounded) < 0.01: + return f"{rounded} mm" + return f"{value:.1f} mm" \ No newline at end of file diff --git a/tests/unit/test_girder_properties.py b/tests/unit/test_girder_properties.py new file mode 100644 index 00000000..5c03ec51 --- /dev/null +++ b/tests/unit/test_girder_properties.py @@ -0,0 +1,29 @@ +from osdagbridge.core.bridge_components.super_structure.girder import properties + + +def test_get_beam_profile_reads_from_resource_db(): + profile = properties.get_beam_profile("WB 500") + + assert profile is not None + assert profile.depth_mm == 500.0 + assert profile.flange_width_mm == 250.0 + assert profile.web_thickness_mm == 9.9 + + +def test_get_rolled_section_returns_outline_dict(): + outline = properties.get_rolled_section("WB 500") + + assert outline == { + "designation": "WB 500", + "depth_mm": 500.0, + "top_flange_width_mm": 250.0, + "bottom_flange_width_mm": 250.0, + "web_thickness_mm": 9.9, + "top_flange_thickness_mm": 14.7, + "bottom_flange_thickness_mm": 14.7, + } + + +def test_unknown_section_returns_none(): + assert properties.get_beam_profile("NON_EXISTENT") is None + assert properties.get_rolled_section("NON_EXISTENT") is None