# BraiLuca v11 - Spline & Circle vadász + Ujjlenyomat adatbázis
# Egyesített verzió: BraiLuca v8 + Ujjlenyomatkereső funkciói
import os
import tkinter as tk
from tkinter import filedialog, messagebox
import ezdxf
import math
import sqlite3
# --- KONFIGURÁCIÓ ---
DB_PATH = (
r"Z:\Temp\!!!INSTALL\Makrok_Hasznos_Kiskesek\BraiLucaBrAlajos\ujjlenyomatok.db"
)
# --- ADATBÁZIS INICIALIZÁLÁS ---
def init_db():
try:
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS fingerprints
(identifier TEXT PRIMARY KEY, fingerprint TEXT)""")
conn.commit()
conn.close()
except Exception as e:
# Ha az adatbázis nem elérhető, csak figyelmeztetünk, nem állunk le
print(f"DB inicializálási hiba: {e}")
# --- BRAILLE MOTOR (VÁLTOZATLAN) ---
class BrailleEngine:
def __init__(self):
self.dot_dist = 2.5
self.char_dist = 6.0
self.row_dist = 10.0
self.tolerance = 0.8
self.b64_chars = (
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
)
def bits_to_base64(self, bit_string):
b64_result = ""
for i in range(0, 480, 6):
six_bits = bit_string[i : i + 6]
val = 0
for bit_pos, bit in enumerate(six_bits):
if bit == "1":
val += 1 << bit_pos
b64_result += self.b64_chars[val]
return b64_result
def get_theoretical_grid(self, offset_x=0, offset_y=0):
grid = []
for row in range(4):
for char in range(20):
for dot_col in range(2):
for dot_row in range(3):
gx = (
(char * self.char_dist)
+ (dot_col * self.dot_dist)
+ offset_x
)
gy = (
-((row * self.row_dist) + (dot_row * self.dot_dist))
+ offset_y
)
grid.append((gx, gy))
return grid
def get_best_fit(self, points):
if not points:
return None, None, False
min_x = min(p[0] for p in points)
max_y = max(p[1] for p in points)
offsets = [(0, 0), (2.5, 0), (0, 2.5), (2.5, 2.5), (0, 5.0), (2.5, 5.0)]
for ox, oy in offsets:
theoretical_grid = self.get_theoretical_grid(min_x - ox, max_y + oy)
fingerprint_bits = ["0"] * 480
snapped_points = []
matched_count = 0
for px, py in points:
for i, (gx, gy) in enumerate(theoretical_grid):
dist = math.sqrt((px - gx) ** 2 + (py - gy) ** 2)
if dist <= self.tolerance:
fingerprint_bits[i] = "1"
snapped_points.append((gx, gy))
matched_count += 1
break
if matched_count == len(points):
is_vertical_shifted = oy != 0
return (
self.bits_to_base64("".join(fingerprint_bits)),
snapped_points,
is_vertical_shifted,
)
return None, None, False
# --- EGYESÍTETT GUI ---
class BraiLuca:
def __init__(self, root):
self.root = root
self.root.title("BraiLuca v11 - Klisé Tisztító & Ujjlenyomat Kezelő")
self.root.geometry("520x620")
self.engine = BrailleEngine()
self.snapped_points = []
self.fingerprint = ""
# ── Fejléc ──────────────────────────────────────────────────
tk.Label(
root, text="BraiLuca - Klisé Tisztító", font=("Arial", 12, "bold")
).pack(pady=8)
# ── DXF megnyitás ────────────────────────────────────────────
self.btn_open = tk.Button(
root, text="DXF Megnyitása", command=self.load_file, height=2, width=30
)
self.btn_open.pack(pady=8)
# ── Státusz keret ────────────────────────────────────────────
self.info_frame = tk.LabelFrame(root, text="Státusz", padx=10, pady=6)
self.info_frame.pack(pady=6, padx=20, fill="x")
self.lbl_dots = tk.Label(self.info_frame, text="Pontok: -")
self.lbl_dots.pack(anchor="w")
self.lbl_fprint = tk.Label(
self.info_frame,
text="Ujjlenyomat: -",
font=("Consolas", 9),
wraplength=440,
)
self.lbl_fprint.pack(anchor="w")
# Ujjlenyomat vágólapra gomb (megmarad)
self.btn_copy = tk.Button(
root,
text="Ujjlenyomat másolása vágólapra",
command=self.copy_to_clipboard,
state="disabled",
)
self.btn_copy.pack(pady=4)
# ── Adatbázis találat keret ──────────────────────────────────
db_frame = tk.LabelFrame(root, text="Adatbázis találat", padx=10, pady=6)
db_frame.pack(pady=6, padx=20, fill="x")
self.entry_res = tk.Entry(
db_frame,
width=60,
font=("Arial", 10, "bold"),
justify="center",
state="readonly",
)
self.entry_res.pack(pady=4)
# ── Új azonosító rögzítése ───────────────────────────────────
save_frame = tk.LabelFrame(root, text="Új azonosító rögzítése", padx=10, pady=6)
save_frame.pack(pady=6, padx=20, fill="x")
id_row = tk.Frame(save_frame)
id_row.pack(fill="x")
tk.Label(id_row, text="Azonosító:").pack(side="left")
self.entry_new_id = tk.Entry(id_row, width=35)
self.entry_new_id.pack(side="left", padx=6)
self.btn_save_db = tk.Button(
save_frame,
text="MENTÉS ÚJ AZONOSÍTÓKÉNT",
command=self.save_new_to_db,
bg="#d4edda",
state="disabled",
)
self.btn_save_db.pack(pady=4)
# ── DXF mentés ───────────────────────────────────────────────
self.btn_save_dxf = tk.Button(
root,
text="Tökéletes DXF mentése (Circle)",
command=self.save_cleaned_dxf,
state="disabled",
bg="#4CAF50",
fg="white",
height=2,
)
self.btn_save_dxf.pack(pady=10)
# ── SEGÉDFÜGGVÉNYEK (VÁLTOZATLAN) ───────────────────────────────
def get_points_from_entity(self, entity, points_list):
dxftype = entity.dxftype()
if dxftype == "CIRCLE":
cp = entity.dxf.center
points_list.append((float(cp.x), float(cp.y)))
elif dxftype == "SPLINE":
cp = entity.control_points
if cp:
avg_x = sum(p[0] for p in cp) / len(cp)
avg_y = sum(p[1] for p in cp) / len(cp)
points_list.append((avg_x, avg_y))
elif dxftype == "INSERT":
for sub_entity in entity.virtual_entities():
self.get_points_from_entity(sub_entity, points_list)
# ── FÁJL BETÖLTÉS (logika változatlan, + auto DB lekérdezés) ────
def load_file(self):
path = filedialog.askopenfilename(filetypes=[("DXF fájlok", "*.dxf")])
if not path:
return
filename = os.path.basename(path)
try:
doc = ezdxf.readfile(path)
msp = doc.modelspace()
all_raw_points = []
for entity in msp:
self.get_points_from_entity(entity, all_raw_points)
if not all_raw_points:
messagebox.showwarning(
"Figyelem", "Nem találtam sem SPLINE, sem CIRCLE elemet a fájlban!"
)
return
# Deduplikáció (változatlan)
unique_points = []
dup_count = 0
for p in all_raw_points:
is_duplicate = False
for u in unique_points:
if math.dist(p, u) < 0.1:
is_duplicate = True
break
if is_duplicate:
dup_count += 1
else:
unique_points.append(p)
status_text = f"Fájl: {filename}\nPontok: {len(unique_points)} db"
if dup_count > 0:
status_text += f" ({dup_count} duplikátum törölve)"
self.lbl_dots.config(text=status_text, fg="black")
fprint, snapped, is_shifted = self.engine.get_best_fit(unique_points)
if fprint:
self.fingerprint = fprint
self.snapped_points = snapped
if is_shifted:
display_text = f"Ujjlenyomat: {self.fingerprint}\n⚠️ FÜGGŐLEGES ELTOLÁS! Célgépen kézi bevitel szükséges!"
self.lbl_fprint.config(text=display_text, fg="red")
else:
self.lbl_fprint.config(
text=f"Ujjlenyomat: {self.fingerprint}", fg="black"
)
self.btn_copy.config(state="normal")
self.btn_save_dxf.config(state="normal")
self.btn_save_db.config(state="normal")
# ── ÚJ: automatikus DB lekérdezés ──
self._search_in_db(self.fingerprint)
else:
self.lbl_fprint.config(text="HIBA: Nem illeszkedik a rácsra!", fg="red")
self.btn_save_dxf.config(state="disabled")
self.btn_save_db.config(state="disabled")
self._clear_db_result()
except Exception as e:
messagebox.showerror("Hiba", f"Beolvasási hiba: {str(e)}")
# ── VÁGÓLAP (VÁLTOZATLAN) ────────────────────────────────────────
def copy_to_clipboard(self):
self.root.clipboard_clear()
self.root.clipboard_append(self.fingerprint)
messagebox.showinfo("Siker", "Vágólapra másolva!")
# ── DB LEKÉRDEZÉS (a második programból áthozva, metódusba szervezve) ──
def _clear_db_result(self):
self.entry_res.config(state="normal")
self.entry_res.delete(0, tk.END)
self.entry_res.config(state="readonly")
def _search_in_db(self, fingerprint):
"""Lekérdezi az ujjlenyomatot az adatbázisból és megjeleníti az eredményt."""
self._clear_db_result()
try:
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute(
"SELECT identifier FROM fingerprints WHERE fingerprint = ?",
(fingerprint,),
)
results = c.fetchall()
conn.close()
self.entry_res.config(state="normal")
if results:
ids = ", ".join([r[0] for r in results])
self.entry_res.insert(0, ids)
self.entry_res.config(fg="navy")
else:
self.entry_res.insert(0, "NINCS MÉG ILYEN UJJLENYOMAT")
self.entry_res.config(fg="gray")
self.entry_res.config(state="readonly")
except Exception as e:
self.entry_res.config(state="normal")
self.entry_res.insert(0, f"DB hiba: {e}")
self.entry_res.config(state="readonly", fg="red")
# ── DB MENTÉS (a második programból áthozva) ─────────────────────
def save_new_to_db(self):
"""Elmenti az ujjlenyomatot az adatbázisba az új azonosítóval.
Visszatér True-val ha sikeres, False-szal ha nem."""
fp = self.fingerprint
new_id = self.entry_new_id.get().strip()
if not new_id:
messagebox.showerror("Hiba", "Kérlek add meg az azonosítót!")
return False
if len(fp) != 80:
messagebox.showerror("Hiba", "Érvénytelen ujjlenyomat (nem 80 karakter)!")
return False
try:
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
# Duplikátum figyelmeztetés (ha ez az ujjlenyomat már létezik)
c.execute(
"SELECT identifier FROM fingerprints WHERE fingerprint = ?", (fp,)
)
exists = c.fetchall()
if exists:
msg = (
f"Ez az ujjlenyomat már szerepel a következő azonosítókkal: "
f"{', '.join([x[0] for x in exists])}\n\n"
f"Biztosan felveszed új azonosítóval ({new_id}) is?"
)
if not messagebox.askyesno("Duplikátum figyelmeztetés", msg):
conn.close()
return False
c.execute(
"INSERT INTO fingerprints (identifier, fingerprint) VALUES (?, ?)",
(new_id, fp),
)
conn.commit()
conn.close()
messagebox.showinfo("Siker", f"'{new_id}' elmentve az adatbázisba!")
self._search_in_db(fp) # Frissítjük a találat mezőt
return True
except sqlite3.IntegrityError:
messagebox.showerror(
"Hiba",
"Ez az AZONOSÍTÓ már foglalt! Minden ujjlenyomatnak egyedi azonosító kell.",
)
return False
except Exception as e:
messagebox.showerror("Hiba", f"DB mentési hiba: {str(e)}")
return False
# ── DXF MENTÉS (Circle logika változatlan, mentési rész bővítve) ─
def save_cleaned_dxf(self):
path = filedialog.asksaveasfilename(
defaultextension=".dxf", filetypes=[("DXF fájlok", "*.dxf")]
)
if not path:
return
new_doc = ezdxf.new("R2000")
try:
new_doc.header["$INSUNITS"] = 4
new_doc.header["$MEASUREMENT"] = 1
except:
try:
new_doc.header.set("$INSUNIT", 4)
except:
pass
new_doc.layers.new(name="Layer1", dxfattribs={"color": 7})
msp = new_doc.modelspace()
for p in self.snapped_points:
msp.add_circle(p, radius=0.8, dxfattribs={"layer": "Layer1"})
new_doc.saveas(path)
messagebox.showinfo("Siker", "A klisé tisztítva és körökké alakítva mentve!")
# ── BELÉPÉSI PONT ────────────────────────────────────────────────────
if __name__ == "__main__":
init_db()
root = tk.Tk()
try:
root.iconbitmap("BrLu.ico")
except:
pass # Ha nincs ico fájl, csendben továbblépünk
app = BraiLuca(root)
root.mainloop()