rev.py Analiza Geodetske kupole

Ovaj program je alat za analizu geodetskih kupola u formatu STL, koji omogućava korisnicima da generišu 3D model letvica (šipki) sa bojama na osnovu dužine ivica i izvoze ga u PLY format. Program takođe računa različite statistike vezane za strukturu kupole, kao što su ukupna dužina letvica, volumen, površina, masa i zapremina kupole, i generiše izveštaj u .txt fajlu.

Evo šta program radi:

  1. Unos fajla i parametara:
    • Program traži od korisnika da unese .stl fajl sa modelom kupole. Ako fajl nije pronađen, program se zaustavlja.
    • Takođe, korisnik unosi parametre za visinu i širinu letvica (šipki) u cm, kao i gustinu drveta u kg/m³. Ako korisnik ne unese vrednosti, koristiće se podrazumevane vrednosti.
  2. Analiza i grupisanje dužina ivica:
    • Program učitava model iz STL fajla i prepoznaje sve ivice kupole.
    • Zatim, grupiše ivice prema njihovoj dužini, koristeći preciznost do dve decimale. Svaka dužina je dodeljena odgovarajućoj boji iz unapred definisane palete boja.
    • Na kraju, ispisuje grupisane dužine ivica sa odgovarajućim brojem pojavljivanja i boje.
  3. Generisanje 3D modela letvica:
    • Za svaku ivicu kupole, program generiše 3D model šipke (letvice) sa odgovarajućom dužinom, visinom i širinom.
    • Svaka šipka je obojena na osnovu svoje dužine.
  4. Eksport u PLY format:
    • Svi modeli šipki se kombinuju u jedan 3D objekat i eksportuju u .ply fajl, koji sadrži geometriju i boje šipki.
    • Ime fajla PLY izlaza se bazira na imenu ulaznog STL fajla, sa dodatkom “_montaza.ply”.
  5. Statistika konstrukcije:
    • Program broji čvorišta (kružne tačke gde se susreću letvice) i prikazuje broj čvorišta sa 3, 4, 5 i 6 letvica.
    • Takođe se izračunavaju statistike kao što su ukupna dužina letvica, volumen, površina kupole, zapremina kupole i masa konstrukcije.
# The MIT License (MIT)
# Copyright (c) 2025 Aleksandar Maričić
# 
# Ovim se omogućava bilo kome da koristi, kopira, menja, spaja, objavljuje, 
# distribuira, daje podlicencu i/ili prodaje kopije ovog softverskog programa, 
# uz uslov da u svim kopijama ili značajnim delovima softverskog programa bude 
# uključena sledeća obavest:
# 
# Copyright (c) 2025 Aleksandar Maričić
# 
# Ovaj softverski program je pružen "takav kakav jeste", bez bilo kakvih garancija, 
# izričitih ili impliciranih, uključujući, ali ne ograničavajući se na, garancije o 
# prikladnosti za prodaju ili pogodnosti za određenu svrhu. U svakom slučaju, autori 
# ili nosioci prava nisu odgovorni za bilo kakvu štetu ili druge obaveze koje mogu nastati 
# usled upotrebe ovog softverskog programa.

import numpy as np
import trimesh
import csv
from collections import Counter, defaultdict
import sys
import os
report_lines = []
report_lines.append("\n🛠️  Izveštaj:")

if len(sys.argv) < 2:
    print("❌ Moraš navesti .stl fajl kao argument! Primer:\npython analiza_kupole.py ime_fajla.stl")
    sys.exit(1)

stl_file = sys.argv[1]

if not os.path.isfile(stl_file):
    print(f"❌ Fajl {stl_file} ne postoji!")
    sys.exit(1)

# Učitavanje STL fajla
dome = trimesh.load_mesh(stl_file)
report_lines.append(f"📂 Učitan je .stl fajl: {stl_file}")
# Traženje visine i širine letvice
try:
    stick_height = float(input("Unesi visinu letvice u cm (npr. 5): ") or 5)
except ValueError:
    stick_height = 5
report_lines.append(f"Visina letvice: {stick_height} cm")
try:
    stick_width = float(input("Unesi širinu letvice u cm (npr. 3): ") or 3)
except ValueError:
    stick_width = 3
report_lines.append(f"Širina letvice: {stick_width} cm")

# Traženje gustine drveta
try:
    gustina_kg_m3 = float(input("Unesi gustinu drveta u kg/m³ (npr. 500): ") or 500)
except ValueError:
    gustina_kg_m3 = 500
report_lines.append(f"Gustinu drveta: {gustina_kg_m3} kg/m³")
# Bazni naziv fajla
file_base = os.path.splitext(os.path.basename(stl_file))[0]

# Pronalazak ivica
edges = dome.edges_unique
edge_lengths = dome.edges_unique_length

# Grupisanje dužina
rounded_lengths = [round(l, 2) for l in edge_lengths]  # Ispravljeno na 2 decimale
length_counter = Counter(rounded_lengths)

# Paleta boja
color_palette = [
    [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0],
    [1.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0],
    [0.5, 0.5, 0.5], [0.8, 0.3, 0.3], [0.3, 0.8, 0.3],
    [0.3, 0.3, 0.8]
]
color_names = {
    (1.0, 0.0, 0.0): 'Crvena',
    (0.0, 1.0, 0.0): 'Zelena',
    (0.0, 0.0, 1.0): 'Plava',
    (1.0, 1.0, 0.0): 'Žuta',
    (1.0, 0.0, 1.0): 'Magenta',
    (0.0, 1.0, 1.0): 'Cijan',
    (0.5, 0.5, 0.5): 'Siva',
    (0.8, 0.3, 0.3): 'Svetlo crvena',
    (0.3, 0.8, 0.3): 'Svetlo zelena',
    (0.3, 0.3, 0.8): 'Svetlo plava'
}

# Mapiranje dužina na boje
length_color_map = {}
for idx, (length, _) in enumerate(sorted(length_counter.items())):
    color = color_palette[idx % len(color_palette)]
    length_color_map[length] = color

# Ispis grupisanih dužina
print("\n📏 Grupisane dužine ivica:")
report_lines.append("\n📏 Grupisane dužine letvica:")
for length, count in sorted(length_counter.items()):
    color_rgb = tuple(length_color_map.get(length, (0.2, 0.2, 0.2)))
    color_name = color_names.get(color_rgb, f"RGB {color_rgb}")
    print(f"{color_name}: {length:.2f} cm -> Broj letvica: {count}")  # Ispis na 2 decimale
    report_lines.append(f"{color_name}: {length:.2f} cm -> Broj letvica: {count} kom.")

# Generisanje 3D modela šipki sa bojama
boxes = []
for edge, raw_length in zip(edges, edge_lengths):
    p1 = dome.vertices[edge[0]]
    p2 = dome.vertices[edge[1]]
    center = (p1 + p2) / 2
    direction = p2 - p1
    length = np.linalg.norm(direction)
    if length == 0:
        continue
    direction /= length
    up = np.array([0, 0, 1])
    if np.allclose(direction, up):
        up = np.array([0, 1, 0])
    side1 = np.cross(up, direction)
    side1 /= np.linalg.norm(side1)
    side2 = np.cross(direction, side1)
    T = np.eye(4)
    T[:3, :3] = np.column_stack([side1 * stick_width, side2 * stick_height, direction * length])
    T[:3, 3] = center
    box = trimesh.creation.box(extents=(1, 1, 1))
    box.apply_transform(T)

    rounded = round(length, 2)  # Ispravljeno na 2 decimale
    color = length_color_map.get(rounded, [0.2, 0.2, 0.2])
    box.visual.vertex_colors = np.tile(color, (box.vertices.shape[0], 1))
    boxes.append(box)

# Eksport
if boxes:
    all_sticks = trimesh.util.concatenate(boxes)
    ply_file = f"{file_base}_montaza.ply"
    all_sticks.export(ply_file)
    print(f"\n💾 Montaža letvica sačuvana kao: {ply_file}")
    report_lines.append(f"\n💾 Montaža letvica sačuvana kao: {ply_file}")

# Brojanje čvorišta
node_connections = defaultdict(int)
for e in edges:
    node_connections[e[0]] += 1
    node_connections[e[1]] += 1

broj_3 = sum(1 for count in node_connections.values() if count == 3)
broj_4 = sum(1 for count in node_connections.values() if count == 4)
broj_5 = sum(1 for count in node_connections.values() if count == 5)
broj_6 = sum(1 for count in node_connections.values() if count == 6)

print("\n🔩 Čvorišta ")
print(f"🔩 Čvorišta sa 3 letvice: {broj_3} kom.")
print(f"🔩 Čvorišta sa 4 letvice: {broj_4} kom.")
print(f"🔩 Čvorišta sa 5 letvica: {broj_5} kom.")
print(f"🔩 Čvorišta sa 6 letvica: {broj_6} kom.")
report_lines.append(f"\n🔩 Čvorišta ")
report_lines.append(f"🔩 Čvorišta sa 3 letvice: {broj_3} kom.")
report_lines.append(f"🔩 Čvorišta sa 4 letvice: {broj_4} kom.")
report_lines.append(f"🔩 Čvorišta sa 5 letvice: {broj_5} kom.")
report_lines.append(f"🔩 Čvorišta sa 6 letvice: {broj_6} kom.")

# Statistika konstrukcije
ukupna_duzina_cm = sum(edge_lengths)
ukupna_duzina_m = ukupna_duzina_cm / 100
volumen_m3 = ukupna_duzina_m * (stick_width / 100) * (stick_height / 100)
povrsina_cm2 = dome.area
povrsina_m2 = povrsina_cm2 / 10000

# Procena zapremine kupole (sferni isečak)
xy_coords = dome.vertices[:, :2]
udaljenosti_od_centra = np.linalg.norm(xy_coords, axis=1)
efektivni_poluprecnik = np.max(udaljenosti_od_centra) / 100
h = (max(dome.vertices[:, 2]) - min(dome.vertices[:, 2])) / 100
zapremina_m3 = (1/3) * np.pi * h**2 * (3 * efektivni_poluprecnik - h)

pokrivena_povrsina_m2 = np.pi * efektivni_poluprecnik**2
masa_kg = volumen_m3 * gustina_kg_m3

print("\n📊 Statistika konstrukcije:")
print(f"📏 Ukupna dužina letvica: {ukupna_duzina_m:.2f} m")
print(f"📦 Kubikaža letvica (za {stick_width}x{stick_height} cm): {volumen_m3:.3f} m³")
print(f"📐 Površina kupole: {povrsina_m2:.2f} m²")
print(f"📐 Zapremina kupole: {zapremina_m3:.2f} m³")
print(f"📐 Površina koju kupola pokriva na tlu: {pokrivena_povrsina_m2:.2f} m²")
print(f"⚖️ Težina drvene konstrukcije: {masa_kg:.2f} kg")
report_lines.append(f"\n📊 Statistika konstrukcije:")
report_lines.append(f"📏 Ukupna dužina letvica: {ukupna_duzina_m:.2f} m")
report_lines.append(f"📦 Kubikaža letvica (za {stick_width}x{stick_height} cm): {volumen_m3:.3f} m³")
report_lines.append(f"📐 Površina kupole: {povrsina_m2:.2f} m²")
report_lines.append(f"📐 Zapremina kupole: {zapremina_m3:.2f} m³")
report_lines.append(f"📐 Površina koju kupola pokriva na tlu: {pokrivena_povrsina_m2:.2f} m²")
report_lines.append(f"⚖️ Težina drvene konstrukcije: {masa_kg:.2f} kg")

# Spremanje izveštaja u .txt fajl
txt_file = f"{file_base}_izvestaj.txt"
with open(txt_file, 'w') as f:
    f.write("\n".join(report_lines))

print(f"\n📄 Izveštaj sačuvan kao: {txt_file}")



Primer upotrebe programa rev.py:

By Abel

Leave a Reply

Your email address will not be published. Required fields are marked *