Predstavljeni Python program služi za generisanje 3D modela spiralne, asimetrične helix zome kupole i eksportovanje rezultata u OBJ format, prikladan za vizualizaciju i dalju obradu u 3D softverima.
Glavne komponente programa:
- Generisanje spirala (
generate_spiral
)
Funkcija kreira set spiralnih linija u 3D prostoru koje čine osnovu kupole. Parametri omogućavaju definisanje broja spirala (n
), broja segmenata po spirali (segs
), prečnika baze kupole (d
), visine (h
), smera uvijanja spirale (direction
), kao i asimetričnog pomaka centra (center_offset
).
Ova funkcija računa koordinate tačaka spiralnih linija koristeći trigonometrijske funkcije, gde se uvijanje i položaj prilagođavaju parametrima kako bi se dobio željeni oblik helix zome. - Pronalazak preseka spirala (
find_intersections
)
Dve grupe spirala – desne i leve – se međusobno presecaju u prostoru. Funkcija traži tačke koje su blizu jedne druge u 3D prostoru (uz zadatu tolerancijutol
) i smatra ih presečnim tačkama.
Ove presečne tačke služe za definisanje čvorova mreže kupole, što je bitno za formiranje čvrste, povezane strukture. - Generisanje wireframe modela (
generate_wireframe_from_intersections
)
Na osnovu pronađenih preseka, ova funkcija pravi OBJ fajl koji sadrži sve tačke (vrhove) i linije koje ih povezuju.
Linije su povezane duž spirala i horizontalno između susednih spirala, stvarajući mrežu koja podseća na zome konstrukciju u vidu helix spirala.
Posebnosti programa:
- Kupola je asimetrična zahvaljujući pomaku centra (
center_offset
), što daje prirodniji, manje simetričan izgled. - Koristi se kombinacija dve grupe spirala koje se uvijaju u suprotnim smerovima (
direction=1
idirection=-1
), što omogućava mrežastu strukturu sa čvrstim presekom. - Eksport je u popularni OBJ format sa definisanim vrhovima i linijama, pogodan za 3D modeliranje, analize i štampu.
Praktična primena:
Ovakav generator može poslužiti arhitektama, inženjerima i entuzijastima 3D modelovanja za stvaranje inovativnih kupolastih konstrukcija, inspirisanih prirodnim i matematičkim formama. Posebno je koristan za istraživanje helix zome struktura sa asimetričnim pomacima i dinamičnim oblikovanjem.

Programski kod HelixA.py
# 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. # Naziv programa: Generator spiralne asimetrične helix zome kupole import numpy as np from math import sin, cos, pi def generate_spiral(n, segs, d, h, direction, center_offset=np.array([0.0, 0.0])): spirals = [] for i in range(n): beta = 2 * pi * i / n spiral = [] for j in range(segs + 1): alpha = pi * j / segs theta = alpha if direction == 1 else -alpha offset_x = center_offset[0] * (alpha / pi) offset_y = center_offset[1] * (alpha / pi) x = sin(theta + beta) * d / 4 + sin(beta) * d / 4 + offset_x y = cos(theta + beta) * d / 4 + cos(beta) * d / 4 + offset_y z = (alpha / pi) * h spiral.append([x, y, z]) spirals.append(np.array(spiral)) return spirals def find_intersections(spirals_right, spirals_left, tol=1e-2): intersections = [] index_map = {} tol2 = tol * tol right_points = [] right_map = [] for si, spiral in enumerate(spirals_right): for pi, p in enumerate(spiral): right_points.append(p) right_map.append((si, pi)) right_points = np.array(right_points) global_idx = 0 for si_left, spiral_left in enumerate(spirals_left): for pi_left, p_left in enumerate(spiral_left): diffs = right_points - p_left dists2 = np.sum(diffs**2, axis=1) close_indices = np.where(dists2 < tol2)[0] if len(close_indices) > 0: key_left = ('L', si_left, pi_left) if key_left not in index_map: index_map[key_left] = global_idx intersections.append(p_left) global_idx += 1 for ci in close_indices: si_right, pi_right = right_map[ci] key_right = ('R', si_right, pi_right) if key_right not in index_map: index_map[key_right] = global_idx intersections.append(right_points[ci]) global_idx += 1 intersections = np.array(intersections) return intersections, index_map def generate_wireframe_from_intersections(filename, spirals_right, spirals_left, index_map): lines = [] def connect_intersections(side, spirals): for si, spiral in enumerate(spirals): intersect_indices = [] for pi in range(len(spiral)): key = (side, si, pi) if key in index_map: intersect_indices.append(index_map[key]) for i in range(len(intersect_indices) - 1): lines.append((intersect_indices[i] + 1, intersect_indices[i + 1] + 1)) connect_intersections('R', spirals_right) connect_intersections('L', spirals_left) # Dodaj horizontalne linije (između spirala) def connect_horizontal_lines(): for side, spirals in [('R', spirals_right), ('L', spirals_left)]: n = len(spirals) segs = len(spirals[0]) for pi in range(segs): for si in range(n): si_next = (si + 1) % n key1 = (side, si, pi) key2 = (side, si_next, pi) if key1 in index_map and key2 in index_map: lines.append((index_map[key1] + 1, index_map[key2] + 1)) connect_horizontal_lines() with open(filename, 'w') as f: global_points = [None] * (max(index_map.values()) + 1) for key, idx in index_map.items(): side, si, pi = key p = spirals_right[si][pi] if side == 'R' else spirals_left[si][pi] global_points[idx] = p for v in global_points: f.write(f"v {v[0]} {v[1]} {v[2]}\n") for line in lines: f.write(f"l {line[0]} {line[1]}\n") print(f"✅ Izvezen wireframe model preseka sa horizontalnim linijama u '{filename}'") # Parametri n = 24 segs = 24 d = 8.0 h = 3 center_offset = np.array([3, 0.0]) tol = 0.02 spirals_right = generate_spiral(n, segs, d, h, direction=1, center_offset=center_offset) spirals_left = generate_spiral(n, segs, d, h, direction=-1, center_offset=center_offset) intersections, index_map = find_intersections(spirals_right, spirals_left, tol=tol) generate_wireframe_from_intersections("spiralna_asimetrična_helix_zome_kupola.obj", spirals_right, spirals_left, index_map)

Konverter OBJ modela u STL format sa triangulacijom
Ovaj Python program služi za konverziju 3D modela iz OBJ formata (koji sadrži vrhove i linije, odnosno žičani model) u STL format koji predstavlja model definisan trouglovima (površinama). Program automatski pronalazi trouglove u žičanom modelu i kreira pravilno orijentisane trouglaste površine pogodne za 3D štampu ili dalje 3D modelovanje.
Kako program funkcioniše:
- Učitavanje OBJ fajla
Program parsira OBJ fajl i čita sve vrhove (v x y z
) i linije (l i j ...
) koje povezuju te vrhove. - Eliminisanje duplikata vrhova
Mnogi OBJ fajlovi imaju vrlo bliske ili duplirane koordinate vrhova. Program kombinuje vrhove koji su udaljeni manje od zadate tolerancije (podrazumevano 0.1) kako bi se smanjio broj vrhova. - Preslikavanje ivica na jedinstvene vrhove
Nakon deduplikacije vrhova, linije se ažuriraju da koriste nove indekse vrhova. - Uklanjanje ukrštenih ivica
Program detektuje ivice koje se preseku u prostoru i uklanja one koje su više usmerene vertikalno, zadržavajući horizontalnije veze. Ovo pomaže da se mreža očisti od neželjenih preseka. - Građenje grafa i pronalaženje trouglova
Na osnovu preostalih ivica gradi se graf susednosti. Trouglovi se pronalaze traženjem trojki čvorova međusobno povezanih ivicama. - Orijentacija normala trouglova
Kako bi se površine pravilno prikazale i model bio konzistentan, orijentacija normala trouglova se proverava i, ako treba, menja tako da gledaju “na spolja”. - Generisanje STL fajla
Na kraju, svi trouglovi se upisuju u STL fajl, spreman za štampu ili druge primene.
Kako se koristi:
Pokretanje iz komandne linije:
python3 obj2stl_trianglovi.py ulazni_fajl.obj izlazni_fajl.stl
ulazni_fajl.obj
— putanja do ulaznog OBJ fajla sa vrhovima i linijama.izlazni_fajl.stl
— putanja gde će biti sačuvan generisani STL fajl.
Zašto koristiti ovaj program?
- Pretvara žičane 3D modele u zatvorene trouglaste površine.
- Automatski pronalazi i pravi trouglove iz linija, čime štedi ručni rad.
- Uklanja problem ukrštanja linija koji može kvariti model.
- Orijentiše normale pravilno za 3D štampu.
- Koristan za brzo pretvaranje mreža u 3D štampljive objekte.
Programski kod za obj2stl.py
# 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. # Naziv programa: Konverter OBJ modela u STL format sa triangulacijom import sys import numpy as np from collections import defaultdict from stl import mesh def parse_obj(filename, tol=1e-3): vertices = [] edges = [] with open(filename, 'r') as f: for line in f: if line.startswith('v '): _, x, y, z = line.strip().split() vertices.append([float(x), float(y), float(z)]) elif line.startswith('l '): parts = line.strip().split() indices = list(map(int, parts[1:])) for i in range(len(indices) - 1): edges.append((indices[i] - 1, indices[i + 1] - 1)) return np.array(vertices), edges def deduplicate_vertices(vertices, tol=1e-1): unique = [] index_map = {} for i, v in enumerate(vertices): for j, u in enumerate(unique): if np.linalg.norm(v - u) < tol: index_map[i] = j break else: index_map[i] = len(unique) unique.append(v) return np.array(unique), index_map def remap_edges(edges, index_map): remapped = [] for a, b in edges: a_m = index_map[a] b_m = index_map[b] if a_m != b_m: remapped.append((a_m, b_m)) return remapped def remove_crossing_edges_keep_horizontal(edges, vertices, tol=1e-5): def segments_intersect(p1, p2, q1, q2): u = p2 - p1 v = q2 - q1 w0 = p1 - q1 a = np.dot(u, u) b = np.dot(u, v) c = np.dot(v, v) d = np.dot(u, w0) e = np.dot(v, w0) denom = a * c - b * b if abs(denom) < 1e-15: return False sc = (b * e - c * d) / denom tc = (a * e - b * d) / denom if not (0 <= sc <= 1 and 0 <= tc <= 1): return False pt1 = p1 + sc * u pt2 = q1 + tc * v return np.linalg.norm(pt1 - pt2) < tol def vertical_angle(p1, p2): v = p2 - p1 norm = np.linalg.norm(v) if norm == 0: return np.pi / 2 horizontal_proj = np.linalg.norm(v[:2]) if horizontal_proj == 0: return np.pi / 2 angle = np.arctan(abs(v[2]) / horizontal_proj) return angle edges_to_keep = set(range(len(edges))) for i in range(len(edges)): if i not in edges_to_keep: continue a1, a2 = edges[i] p1, p2 = vertices[a1], vertices[a2] for j in range(i + 1, len(edges)): if j not in edges_to_keep: continue b1, b2 = edges[j] if len({a1, a2, b1, b2}) < 4: continue q1, q2 = vertices[b1], vertices[b2] if segments_intersect(p1, p2, q1, q2): angle_i = vertical_angle(p1, p2) angle_j = vertical_angle(q1, q2) if angle_i <= angle_j: edges_to_keep.discard(j) else: edges_to_keep.discard(i) break return [edges[i] for i in sorted(edges_to_keep)] def build_graph(edges, num_vertices): graph = defaultdict(set) for a, b in edges: if a != b: graph[a].add(b) graph[b].add(a) return graph def find_triangles(graph): triangles = set() for a in graph: neighbors_a = graph[a] for b in neighbors_a: if b <= a: continue neighbors_b = graph[b] common = neighbors_a.intersection(neighbors_b) for c in common: if c > b: triangle = tuple(sorted([a, b, c])) triangles.add(triangle) return list(triangles) def compute_normal(v1, v2, v3): return np.cross(v2 - v1, v3 - v1) def get_centroid(vertices): return np.mean(vertices, axis=0) def ensure_outward_normals(triangles, vertices): centroid = get_centroid(vertices) corrected_triangles = [] for tri in triangles: v1, v2, v3 = tri normal = compute_normal(v1, v2, v3) tri_center = np.mean([v1, v2, v3], axis=0) vec_from_centroid = tri_center - centroid if np.dot(normal, vec_from_centroid) < 0: tri = [v1, v3, v2] corrected_triangles.append(tri) return corrected_triangles if __name__ == "__main__": if len(sys.argv) != 3: print("Upotreba: python3 obj2stl_trianglovi.py ulaz.obj izlaz.stl") sys.exit(1) obj_path = sys.argv[1] stl_path = sys.argv[2] print(f"🔍 Učitavanje OBJ: {obj_path}") verts_raw, edges = parse_obj(obj_path) print(f"📌 Učitano {len(verts_raw)} vrhova i {len(edges)} linija.") verts, idx_map = deduplicate_vertices(verts_raw) print(f"🔄 Eliminisano na {len(verts)} jedinstvenih vrhova.") edges_mapped = remap_edges(edges, idx_map) print(f"🔄 Preslikani ivice na deduplicirane vrhove: {len(edges_mapped)} linija.") edges_clean = remove_crossing_edges_keep_horizontal(edges_mapped, verts) print(f"🧹 Uklonjeno {len(edges_mapped) - len(edges_clean)} ukrštenih linija.") graph = build_graph(edges_clean, len(verts)) triangles_indices = find_triangles(graph) print(f"🔺 Pronađeno {len(triangles_indices)} trouglova.") # Pretvori indekse trouglova u vrhove triangles = [] for tri_idx in triangles_indices: tri_vertices = [verts[i] for i in tri_idx] triangles.append(tri_vertices) # Osiguraj da su trouglovi orijentisani spolja triangles = ensure_outward_normals(triangles, verts) # Kreiraj STL stl_data = mesh.Mesh(np.zeros(len(triangles), dtype=mesh.Mesh.dtype)) for i, tri in enumerate(triangles): stl_data.vectors[i] = np.array(tri) stl_data.save(stl_path) print(f"✅ Sačuvan STL: {stl_path} ({len(triangles)} trouglova)")

Konvertor OBJ žičanih modela u obojeni PLY format sa cilindričnim šipkama
Ovaj Python program omogućava konverziju 3D žičanih modela iz OBJ formata (sa definisanim vrhovima i linijama) u PLY format koji koristi cilindrične štapove (cevi) za prikaz ivica, sa izabranom bojom. Program generiše geometriju šipki između vrhova i čuva model u standardnom PLY fajlu sa RGB bojom.
Kako program radi:
- Učita OBJ fajl i izvlači vrhove i linije (ivice).
- Koristi definisanu debljinu i broj segmenata da na svakoj liniji napravi trodimenzionalni cilindar kao 3D geometrijski objekat.
- Omogućava korisniku da izabere boju šipki iz ponuđenog menija.
- Kreira PLY fajl koji sadrži vertexe i trouglaste površine cilindara, sa dodatim RGB vrednostima boje za svaki vertex.
- Čuva rezultat u istom direktorijumu, sa istim imenom kao ulazni fajl, ali sa ekstenzijom
.ply
.
Kako koristiti program:
- Pokrenite program iz komandne linije sa ulaznim OBJ fajlom:
python3 obj2ply.py model.obj
- Program će prikazati meni sa bojama. Unesite broj boje koju želite za model (npr.
4
za plavu). - Nakon obrade, u istom folderu će biti kreiran
model.ply
fajl sa cilindričnim šipkama u izabranoj boji.
Ključne karakteristike:
- Cilindrična reprezentacija ivica: Svaka linija u OBJ fajlu pretvara se u 3D cilindar, što omogućava lepši i realističniji prikaz šipkastih konstrukcija.
- Više ponuđenih boja: Korisnik može lako da bira boju šipki putem jednostavnog menija.
- Jednostavna upotreba: Program se koristi samo sa jednim argumentom – ulaznim OBJ fajlom.
- Otvoreni kod sa MIT licencom: Može se slobodno koristiti i prilagođavati uz navođenje autora.
Programski kod za obj2ply.py
# 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. # Naziv programa: KONVERTOR IZ OBJ U PLY import numpy as np import sys from pathlib import Path RADIUS = 0.01 CYLINDER_SEGMENTS = 16 # Definiši dostupne boje kao RGB (0-255) BOJE = { 1: ("bela", (255, 255, 255)), 2: ("crvena", (255, 0, 0)), 3: ("zelena", (0, 255, 0)), 4: ("plava", (0, 0, 255)), 5: ("žuta", (255, 255, 0)), 6: ("ljubičasta", (128, 0, 128)), 7: ("narandžasta", (255, 165, 0)), 8: ("tirkizna", (64, 224, 208)), 9: ("siva", (128, 128, 128)), 10: ("crna", (0, 0, 0)), } def prikazi_meni_i_uzmi_boju(): print("Izaberite boju modela:") for broj, (ime, rgb) in sorted(BOJE.items()): print(f"{broj}. {ime} (RGB: {rgb})") while True: try: izbor = int(input("Unesite broj boje: ")) if izbor in BOJE: return BOJE[izbor][1] else: print("Nepoznat broj boje, pokušajte ponovo.") except ValueError: print("Molimo unesite ceo broj.") def ucitaj_obj(path): vertices = [] edges = [] with open(path, "r") as f: for line in f: if line.startswith("v "): _, x, y, z = line.strip().split() vertices.append(np.array([float(x), float(y), float(z)])) elif line.startswith("l "): parts = line.strip().split() edges.append((int(parts[1]) - 1, int(parts[2]) - 1)) return vertices, edges def napravi_cilindar(p1, p2, radius, segments=16): v = p2 - p1 length = np.linalg.norm(v) if length < 1e-8: return [], [] axis = v / length if abs(axis[0]) < 0.001 and abs(axis[1]) < 0.001: ortho = np.array([1, 0, 0]) else: ortho = np.array([0, 0, 1]) n1 = np.cross(axis, ortho) n1 /= np.linalg.norm(n1) n2 = np.cross(axis, n1) n2 /= np.linalg.norm(n2) circle_p1 = [] circle_p2 = [] for i in range(segments): theta = 2 * np.pi * i / segments dir_vec = np.cos(theta) * n1 + np.sin(theta) * n2 circle_p1.append(p1 + radius * dir_vec) circle_p2.append(p2 + radius * dir_vec) vertices = circle_p1 + circle_p2 faces = [] for i in range(segments): i_next = (i + 1) % segments faces.append((i, i_next, i_next + segments)) faces.append((i, i_next + segments, i + segments)) return vertices, faces def sacuvaj_ply(verts, faces, filename, boja): r, g, b = boja with open(filename, "w") as f: f.write("ply\n") f.write("format ascii 1.0\n") f.write(f"element vertex {len(verts)}\n") f.write("property float x\nproperty float y\nproperty float z\n") # Dodajemo RGB atribute f.write("property uchar red\nproperty uchar green\nproperty uchar blue\n") f.write(f"element face {len(faces)}\n") f.write("property list uchar int vertex_indices\n") f.write("end_header\n") for v in verts: f.write(f"{v[0]} {v[1]} {v[2]} {r} {g} {b}\n") for face in faces: f.write(f"3 {face[0]} {face[1]} {face[2]}\n") def main(): if len(sys.argv) != 2: print("Upotreba: python3 obj2ply.py ulazni_fajl.obj") return input_path = Path(sys.argv[1]) if not input_path.exists(): print(f"Fajl ne postoji: {input_path}") return boja = prikazi_meni_i_uzmi_boju() output_path = input_path.with_suffix(".ply") vertices, edges = ucitaj_obj(input_path) print(f"Učitano {len(vertices)} tačaka i {len(edges)} ivica iz {input_path}") sve_verteksi = [] sve_face = [] offset = 0 for i1, i2 in edges: p1 = vertices[i1] p2 = vertices[i2] verts_cil, faces_cil = napravi_cilindar(p1, p2, RADIUS, CYLINDER_SEGMENTS) sve_verteksi.extend(verts_cil) for f in faces_cil: sve_face.append((f[0] + offset, f[1] + offset, f[2] + offset)) offset += len(verts_cil) sacuvaj_ply(sve_verteksi, sve_face, output_path, boja) print(f"Ply fajl sa šipkama sačuvan kao: {output_path}") if __name__ == "__main__": main()

Konvertor OBJ modela u DXF format
Ovaj Python program omogućava konverziju 3D žičanih modela iz OBJ formata u DXF format. Program učitava vrhove i linije iz OBJ fajla i u DXF fajlu ih prenosi kao linijske entitete, što olakšava rad u CAD programima poput AutoCAD-a.
Kako program funkcioniše:
- Učitava OBJ fajl i parsira vrhove (
v x y z
) i linije (l i j
) koje povezuju te vrhove. - Kreira novi DXF dokument koristeći biblioteku
ezdxf
. - Dodaje linije između odgovarajućih tačaka u model prostor DXF fajla.
- Čuva rezultat kao DXF fajl sa istim imenom kao ulazni, ali sa
.dxf
ekstenzijom.
Kako koristiti program:
- Pokrenite program iz komandne linije sa ulaznim OBJ fajlom:
python3 obj2dxf.py model.obj
- Program će automatski kreirati
model.dxf
u istom direktorijumu.
Prednosti:
- Jednostavan i brz način da se OBJ žičani modeli prenesu u CAD okruženje.
- Koristi standardni DXF format verzije R2010.
- Ne zahteva dodatnu konfiguraciju osim zadavanja ulaznog fajla.
Programski kod za obj2dxf.py
# 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. # Naziv programa: KONVERTOR IZ OBJ U DXF import ezdxf import sys from pathlib import Path def read_obj_vertices_and_lines(filename): vertices = [] lines = [] with open(filename, 'r') as f: for line in f: if line.startswith('v '): parts = line.strip().split() x, y, z = float(parts[1]), float(parts[2]), float(parts[3]) vertices.append((x, y, z)) elif line.startswith('l '): parts = line.strip().split() i1 = int(parts[1]) - 1 i2 = int(parts[2]) - 1 lines.append((i1, i2)) return vertices, lines def obj_to_dxf(obj_file, dxf_file): vertices, lines = read_obj_vertices_and_lines(obj_file) doc = ezdxf.new(dxfversion="R2010") msp = doc.modelspace() for i1, i2 in lines: p1 = vertices[i1] p2 = vertices[i2] msp.add_line(p1, p2) doc.saveas(dxf_file) print(f"✅ Sačuvan: {dxf_file}") def main(): if len(sys.argv) != 2: print("Upotreba: python3 obj2dxf.py ulazni_fajl.obj") return input_path = Path(sys.argv[1]) if not input_path.exists(): print(f"❌ Fajl ne postoji: {input_path}") return output_path = input_path.with_suffix('.dxf') obj_to_dxf(str(input_path), str(output_path)) if __name__ == "__main__": main()
Linkovi: