# =================================================================== # extraer_combos_sap.py # Función standalone para extraer combinaciones de SAP2000 # =================================================================== import os import tkinter as tk from tkinter.filedialog import asksaveasfilename from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side, NamedStyle from openpyxl.utils import get_column_letter # Colores exactos de SAP2000 AZUL_TITULO = "33CCCC" # Azul oscurito título AZUL_SAP = "CCFFFF" # Azul marino cabecera # Barra de progreso (la misma que usas en el script principal) def printProgressBar(iteration, total, prefix='', suffix='', decimals=1, length=50, fill='█'): percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filledLength = int(length * iteration // total) bar = fill * filledLength + '-' * (length - filledLength) print(f'\r{prefix} |{bar}| {percent}% {suffix}', end="") if iteration == total: print() def extraer_combinaciones_a_excel(SapModel, ruta_excel_origen=None): """ Extrae todas las combinaciones de SAP2000 y las guarda en Excel con el formato EXACTO del reporte oficial de SAP2000. Parámetros: SapModel: objeto SAP2000 ya conectado ruta_excel_origen: (opcional) ruta del Excel original para sugerir nombre y carpeta """ # --- Ventana para guardar --- root = tk.Tk() root.withdraw() root.attributes('-topmost', True) # Sugerir nombre y carpeta inteligente if ruta_excel_origen and os.path.exists(ruta_excel_origen): nombre_base = os.path.splitext(os.path.basename(ruta_excel_origen))[0] nombre_sugerido = f"{nombre_base}_COMBINACIONES_SAP2000.xlsx" initialfile = nombre_sugerido else: initialfile = "COMBINACIONES_SAP2000.xlsx" archivo_salida = asksaveasfilename( initialfile=initialfile, defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")], title="Guardar combinaciones (formato SAP2000)" ) root.destroy() if not archivo_salida: print("\nExportación cancelada por el usuario.") return # --- Extraer combinaciones --- ret = SapModel.RespCombo.GetNameList() num_combos = ret[0] combo_names = ret[1] datos = [] for i, combo_name in enumerate(combo_names): tipo = SapModel.RespCombo.GetTypeOAPI(combo_name)[0] tipo_texto = "Linear Add" if tipo == 0 else "Envelope" if tipo == 1 else "Other" casos = SapModel.RespCombo.GetCaseList(combo_name) nombres_casos = casos[2] factores = casos[3] if len(nombres_casos) == 0: datos.append([combo_name, tipo_texto, "", ""]) else: for j, caso in enumerate(nombres_casos): if j == 0: datos.append([combo_name, tipo_texto, caso, factores[j]]) else: datos.append(["", "", caso, factores[j]]) printProgressBar(i + 1, num_combos, prefix="Progreso:", suffix="Completado", length=50) # --- Crear Excel con formato idéntico a SAP2000 --- wb = Workbook() ws = wb.active ws.title = "Combinaciones" # 1. Título ws['A1'] = "TABLE: Combination Definitions" ws['A1'].font = Font(name="Arial Narrow", size=11, bold=True) ws['A1'].alignment = Alignment(horizontal="center") ws['A1'].fill = PatternFill(start_color=AZUL_TITULO, end_color=AZUL_TITULO, fill_type="solid") ws.merge_cells('A1:D1') # 2. Cabeceras (azul marino SAP2000) cabeceras = ["ComboName", "ComboType", "CaseName", "ScaleFactor"] for c, texto in enumerate(cabeceras, 1): cell = ws.cell(row=2, column=c, value=texto) cell.font = Font(name="Arial Narrow", bold=True, color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 3. Tipos de datos (amarillo SAP2000) tipos = ["Text", "Text", "Text", "Unitless"] for c, texto in enumerate(tipos, 1): cell = ws.cell(row=3, column=c, value=texto) cell.font = Font(name="Arial Narrow", color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 4. Datos for r, fila in enumerate(datos, start=4): for c, valor in enumerate(fila, 1): cell = ws.cell(row=r, column=c, value=valor) cell.font = Font(name="Arial Narrow", size=10) # Aplicar borde fino a todas las celdas thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for row in ws.iter_rows(): for cell in row: cell.border = thin_border # Autoajustar columnas según el contenido (excluyendo la primera fila que está fusionada) column_widths = {1: 18, 2: 12, 3: 25, 4: 12} # Anchos por defecto for row in ws.iter_rows(min_row=2, max_row=ws.max_row): # Comienza desde fila 2 for col_idx, cell in enumerate(row, 1): if cell.value: cell_len = len(str(cell.value)) if col_idx in column_widths: column_widths[col_idx] = max(column_widths[col_idx], cell_len) for col_idx, width in column_widths.items(): ws.column_dimensions[get_column_letter(col_idx)].width = width # Guardar wb.save(archivo_salida) def extraer_flechas(SapModel, ruta_excel_origen=None, var_flechas=None): """ Función placeholder para extraer flechas. Actualmente no implementada. """ # --- Ventana para guardar --- root = tk.Tk() root.withdraw() root.attributes('-topmost', True) # Sugerir nombre y carpeta inteligente if ruta_excel_origen and os.path.exists(ruta_excel_origen): nombre_base = os.path.splitext(os.path.basename(ruta_excel_origen))[0] nombre_sugerido = f"{nombre_base}_DESPLAZAMIENTOS_SAP2000.xlsx" initialfile = nombre_sugerido else: initialfile = "DESPLAZAMIENTOS_SAP2000.xlsx" archivo_salida = asksaveasfilename( initialfile=initialfile, defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")], title="Guardar desplazamientos (formato SAP2000)" ) root.destroy() if not archivo_salida: print("\nExportación cancelada por el usuario.") return # Obtener desplazamientos en nudos FieldKeyList = [] GroupName = 'All' TableVersion = 1 FieldsKeysIncluded = [] NumberRecords = 1 TableData = [] SapModel.SetPresentUnits(9) # Unidades niutons milimetos ret = SapModel.Results.Setup.DeselectAllCasesAndCombosForOutput() ret = SapModel.Results.Setup.SetComboSelectedForOutput(var_flechas) ret = SapModel.DatabaseTables.GetTableforDisplayArray("Joint Displacements", FieldKeyList, GroupName, TableVersion, FieldsKeysIncluded, NumberRecords, TableData) datos = [] for i in range(int(len(ret[4])/10)): datos.append([ret[4][i*10], ret[4][i*10+1], ret[4][i*10+2], ret[4][i*10+3], ret[4][i*10+4], ret[4][i*10+5], ret[4][i*10+6], ret[4][i*10+7], ret[4][i*10+8], ret[4][i*10+9]]) # --- Crear Excel con formato idéntico a SAP2000 --- wb = Workbook() ws = wb.active ws.title = "Desplazamientos" #se ajustan los decimales flecha_style = NamedStyle(name="flecha_style", number_format="0.00", font=Font(name="Arial Narrow", size=10)) giro_style = NamedStyle(name="giro_style", number_format="0.0000", font=Font(name="Arial Narrow", size=10)) wb.add_named_style(flecha_style) wb.add_named_style(giro_style) # 1. Título ws['A1'] = "TABLE: Joint Displacements" ws['A1'].font = Font(name="Arial Narrow", size=11, bold=True) ws['A1'].alignment = Alignment(horizontal="center") ws['A1'].fill = PatternFill(start_color=AZUL_TITULO, end_color=AZUL_TITULO, fill_type="solid") ws.merge_cells('A1:J1') # 2. Cabeceras (azul marino SAP2000) cabeceras = ret[2] for c, texto in enumerate(cabeceras, 1): cell = ws.cell(row=2, column=c, value=texto) cell.font = Font(name="Arial Narrow", bold=True, color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 3. Tipos de datos (amarillo SAP2000) tipos = ["Text", "Text", "Text", "Text", "Length (mm)", "Length (mm)", "Length (mm)", "Angle", "Angle", "Angle"] for c, texto in enumerate(tipos, 1): cell = ws.cell(row=3, column=c, value=texto) cell.font = Font(name="Arial Narrow", color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 4. Datos for r, fila in enumerate(datos, start=4): for c, valor in enumerate(fila, 1): cell = ws.cell(row=r, column=c, value=valor) if c > 4: try: cell.value = float(valor.replace(',', '.')) # Asegurarse de que es float except ValueError: cell.value = valor cell.font = Font(name="Arial Narrow", size=10) num_rows = ws.max_row for row in range(4, num_rows + 1): for col in ['E', 'F', 'G']: # UX, UY, UZ (flechas) ws[f'{col}{row}'].style = flecha_style for col in ['H', 'I', 'J']: # RX, RY, RZ (giros) ws[f'{col}{row}'].style = giro_style # Aplicar borde fino a todas las celdas thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for row in ws.iter_rows(): for cell in row: cell.border = thin_border # Autoajustar columnas según el contenido (excluyendo la primera fila que está fusionada) column_widths = {1: 18, 2: 12, 3: 25, 4: 12, 5: 12, 6: 12, 7: 12, 8: 12, 9: 12, 10: 12} # Anchos por defecto for row in ws.iter_rows(min_row=2, max_row=ws.max_row): # Comienza desde fila 2 for col_idx, cell in enumerate(row, 1): if cell.value: cell_len = len(str(cell.value)) if col_idx in column_widths: column_widths[col_idx] = max(column_widths[col_idx], cell_len) for col_idx, width in column_widths.items(): ws.column_dimensions[get_column_letter(col_idx)].width = width # Guardar wb.save(archivo_salida) def extraer_esfuerzos(SapModel, ruta_excel_origen=None, var_esfuerzos=None): """ Función placeholder para extraer flechas. Actualmente no implementada. """ # --- Ventana para guardar --- root = tk.Tk() root.withdraw() root.attributes('-topmost', True) # Sugerir nombre y carpeta inteligente if ruta_excel_origen and os.path.exists(ruta_excel_origen): nombre_base = os.path.splitext(os.path.basename(ruta_excel_origen))[0] nombre_sugerido = f"{nombre_base}_ESFUERZOS_SAP2000.xlsx" initialfile = nombre_sugerido else: initialfile = "ESFUERZOS_SAP2000.xlsx" archivo_salida = asksaveasfilename( initialfile=initialfile, defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")], title="Guardar esfuerzos (formato SAP2000)" ) root.destroy() if not archivo_salida: print("\nExportación cancelada por el usuario.") return # Obtener desplazamientos en nudos FieldKeyList = [] GroupName = 'All' TableVersion = 1 FieldsKeysIncluded = [] NumberRecords = 1 TableData = [] SapModel.SetPresentUnits(6) # Unidades niutons milimetos ret = SapModel.Results.Setup.DeselectAllCasesAndCombosForOutput() ret = SapModel.Results.Setup.SetComboSelectedForOutput(var_esfuerzos) ret = SapModel.DatabaseTables.GetTableforDisplayArray("Element Forces - Frames", FieldKeyList, GroupName, TableVersion, FieldsKeysIncluded, NumberRecords, TableData) datos = [] for i in range(int(len(ret[4])/13)): datos.append([ret[4][i*13], ret[4][i*13+1], ret[4][i*13+2], ret[4][i*13+3], ret[4][i*13+4], ret[4][i*13+5], ret[4][i*13+6], ret[4][i*13+7], ret[4][i*13+8], ret[4][i*13+9], ret[4][i*13+10], ret[4][i*13+11], ret[4][i*13+12]]) # --- Crear Excel con formato idéntico a SAP2000 --- wb = Workbook() ws = wb.active ws.title = "Desplazamientos" #se ajustan los decimales flecha_style = NamedStyle(name="flecha_style", number_format="0.00", font=Font(name="Arial Narrow", size=10)) giro_style = NamedStyle(name="giro_style", number_format="0.0000", font=Font(name="Arial Narrow", size=10)) wb.add_named_style(flecha_style) wb.add_named_style(giro_style) # 1. Título ws['A1'] = "TABLE: Joint Displacements" ws['A1'].font = Font(name="Arial Narrow", size=11, bold=True) ws['A1'].alignment = Alignment(horizontal="center") ws['A1'].fill = PatternFill(start_color=AZUL_TITULO, end_color=AZUL_TITULO, fill_type="solid") ws.merge_cells('A1:M1') # 2. Cabeceras (azul marino SAP2000) cabeceras = ret[2] for c, texto in enumerate(cabeceras, 1): cell = ws.cell(row=2, column=c, value=texto) cell.font = Font(name="Arial Narrow", bold=True, color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 3. Tipos de datos (amarillo SAP2000) tipos = ["Text", "m", "Text", "Text", "Text", "kN", "kN", "kN", "kNm", "kNm", "kNm", "Text", "Text"] for c, texto in enumerate(tipos, 1): cell = ws.cell(row=3, column=c, value=texto) cell.font = Font(name="Arial Narrow", color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 4. Datos for r, fila in enumerate(datos, start=4): for c, valor in enumerate(fila, 1): cell = ws.cell(row=r, column=c, value=valor) if ((c > 5) and (c < 12)) or (c==2): try: cell.value = float(valor.replace(',', '.')) # Asegurarse de que es float except ValueError: cell.value = valor cell.font = Font(name="Arial Narrow", size=10) num_rows = ws.max_row for row in range(4, num_rows + 1): for col in ['B','F', 'F', 'G', 'H', 'I', 'J', 'K']: # UX, UY, UZ (flechas) ws[f'{col}{row}'].style = flecha_style # Aplicar borde fino a todas las celdas thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for row in ws.iter_rows(): for cell in row: cell.border = thin_border # Autoajustar columnas según el contenido (excluyendo la primera fila que está fusionada) column_widths = {1: 18, 2: 12, 3: 25, 4: 12, 5: 12, 6: 12, 7: 12, 8: 12, 9: 12, 10: 12, 11: 12, 12: 12, 13: 12} # Anchos por defecto for row in ws.iter_rows(min_row=2, max_row=ws.max_row): # Comienza desde fila 2 for col_idx, cell in enumerate(row, 1): if cell.value: cell_len = len(str(cell.value)) if col_idx in column_widths: column_widths[col_idx] = max(column_widths[col_idx], cell_len) for col_idx, width in column_widths.items(): ws.column_dimensions[get_column_letter(col_idx)].width = width # Guardar wb.save(archivo_salida)