ویرگول
ورودثبت نام
lordtec
lordtec
lordtec
lordtec
خواندن ۵ دقیقه·۳ ماه پیش

ماشین حساب مهندسی پیشرفته با رسم نمودار دوبعدی و سه بعدی

ماشین حساب مهندسی پیشرفته با رسم نمودار دوبعدی و سه بعدی
ماشین حساب مهندسی پیشرفته با رسم نمودار دوبعدی و سه بعدی
#خب اولین کارمون رایگان در اختیار شما # scientific_calculator_3d.py """ ماشینحساب مهندسی با رسم 2D و 3D (z = f(x,y)) - امنسازی eval با توابع math و numpy محدود - رسم دوبعدی f(x) و رسم سهبعدی z=f(x,y) با matplotlib (Axes3D) """ import tkinter as tk from tkinter import ttk, filedialog, messagebox import math import numpy as np import matplotlib matplotlib.use("TkAgg") from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from mpl_toolkits.mplot3d import Axes3D # noqa: F401 import sympy as sp import traceback # --- امنسازی محیط eval --- _safe_dict = {} for name in dir(math): if not name.startswith("_"): _safe_dict[name] = getattr(math, name) # allowed numpy functions (limited) _np_allowed = ["sin", "cos", "tan", "arcsin", "arccos", "arctan", "sinh", "cosh", "tanh", "exp", "log", "log10", "sqrt", "abs", "pi", "e", "sin", "cos"] for name in _np_allowed: if hasattr(np, name): _safe_dict["np_"+name] = getattr(np, name) def safe_eval(expr, local_vars=None): if local_vars is None: local_vars = {} expr = expr.replace("^", "**") env = dict(_safe_dict) # expose math names directly for name in dir(math): if not name.startswith("_"): env[name] = getattr(math, name) # limited numpy as dict under 'np' limited_np = {} for name in set(_np_allowed): if hasattr(np, name): limited_np[name] = getattr(np, name) limited_np["pi"] = np.pi limited_np["e"] = np.e env["np"] = limited_np env.update(local_vars) env["__builtins__"] = {} return eval(expr, env) # --- GUI --- class ScientificCalculator3D(tk.Tk): def __init__(self): super().__init__() self.title("ماشینحساب مهندسی 2D/3D") self.geometry("1200x780") self.resizable(True, True) self.expr_var = tk.StringVar() self.result_var = tk.StringVar() self.plot_expr = tk.StringVar(value="sin(x)") self.plot3_expr = tk.StringVar(value="sin(x*y)") self.history = [] self._build_ui() def _build_ui(self): top = ttk.Frame(self) top.pack(side="top", fill="x", padx=8, pady=6) entry = ttk.Entry(top, textvariable=self.expr_var, font=("Consolas", 18)) entry.pack(side="left", fill="x", expand=True, padx=(0,6)) entry.bind("<Return>", lambda e: self.evaluate()) ttk.Label(top, textvariable=self.result_var, font=("Consolas", 14)).pack(side="right") main = ttk.Frame(self) main.pack(fill="both", expand=True) left = ttk.Frame(main) left.pack(side="left", fill="y", padx=6, pady=6) btns = [ ["7","8","9","/","sqrt("], ["4","5","6","*","^"], ["1","2","3","-","("], ["0",".","%","+",")"], ["pi","e","ans","C","DEL"] ] for r,row in enumerate(btns): rf = ttk.Frame(left); rf.pack(pady=2) for txt in row: ttk.Button(rf, text=txt, width=6, command=lambda t=txt: self.on_button(t)).pack(side="left", padx=2) func_frame = ttk.LabelFrame(left, text="Functions") func_frame.pack(pady=6) funcs = ["sin(","cos(","tan(","asin(","acos(","atan(","sinh(","cosh(","tanh(","log(","log10(","exp(","abs(","factorial("] for i,fn in enumerate(funcs): ttk.Button(func_frame, text=fn.rstrip("("), width=8, command=lambda f=fn: self.on_button(f)).grid(row=i//3, column=i%3, padx=2, pady=2) mid = ttk.Frame(main) mid.pack(side="left", fill="y", padx=6, pady=6) ttk.Button(mid, text="=", width=20, command=self.evaluate).pack(pady=6) ttk.Button(mid, text="Clear All", width=20, command=self.clear_all).pack(pady=6) hist_frame = ttk.LabelFrame(mid, text="History") hist_frame.pack(fill="both", expand=True) self.hist_list = tk.Listbox(hist_frame, height=12, width=30) self.hist_list.pack(side="left", fill="both", expand=True) ttk.Scrollbar(hist_frame, orient="vertical", command=self.hist_list.yview).pack(side="right", fill="y") self.hist_list.config(yscrollcommand=lambda *args: None) self.hist_list.bind("<Double-Button-1>", self.on_history_select) right = ttk.Frame(main) right.pack(side="right", fill="both", expand=True, padx=6, pady=6) # Plot 2D plot2 = ttk.LabelFrame(right, text="Plot 2D: f(x)") plot2.pack(fill="x", pady=4) ttk.Label(plot2, text="f(x)=").grid(row=0,column=0, sticky="w") ttk.Entry(plot2, textvariable=self.plot_expr, width=40).grid(row=0,column=1,columnspan=3, sticky="w") ttk.Label(plot2, text="xmin").grid(row=1,column=0, sticky="w") self.xmin_var = tk.StringVar(value="-10"); ttk.Entry(plot2, textvariable=self.xmin_var, width=8).grid(row=1,column=1) ttk.Label(plot2, text="xmax").grid(row=1,column=2, sticky="w") self.xmax_var = tk.StringVar(value="10"); ttk.Entry(plot2, textvariable=self.xmax_var, width=8).grid(row=1,column=3) ttk.Label(plot2, text="samples").grid(row=2,column=0, sticky="w") self.samples_var = tk.IntVar(value=1000); ttk.Entry(plot2, textvariable=self.samples_var, width=8).grid(row=2,column=1) ttk.Button(plot2, text="Plot 2D", command=self.plot_2d).grid(row=3,column=0, pady=6) ttk.Button(plot2, text="Save PNG", command=self.save_plot).grid(row=3,column=1, pady=6) ttk.Button(plot2, text="Clear", command=self.clear_plot).grid(row=3,column=2, pady=6) # Plot 3D plot3 = ttk.LabelFrame(right, text="Plot 3D: z=f(x,y)") plot3.pack(fill="x", pady=4) ttk.Label(plot3, text="z=").grid(row=0,column=0, sticky="w") ttk.Entry(plot3, textvariable=self.plot3_expr, width=40).grid(row=0,column=1,columnspan=3, sticky="w") ttk.Label(plot3, text="xmin").grid(row=1,column=0, sticky="w") self.x3_min = tk.StringVar(value="-5"); ttk.Entry(plot3, textvariable=self.x3_min, width=8).grid(row=1,column=1) ttk.Label(plot3, text="xmax").grid(row=1,column=2, sticky="w") self.x3_max = tk.StringVar(value="5"); ttk.Entry(plot3, textvariable=self.x3_max, width=8).grid(row=1,column=3) ttk.Label(plot3, text="ymin").grid(row=2,column=0, sticky="w") self.y3_min = tk.StringVar(value="-5"); ttk.Entry(plot3, textvariable=self.y3_min, width=8).grid(row=2,column=1) ttk.Label(plot3, text="ymax").grid(row=2,column=2, sticky="w") self.y3_max = tk.StringVar(value="5"); ttk.Entry(plot3, textvariable=self.y3_max, width=8).grid(row=2,column=3) ttk.Label(plot3, text="samples (each axis)").grid(row=3,column=0, sticky="w") self.samples3_var = tk.IntVar(value=200); ttk.Entry(plot3, textvariable=self.samples3_var, width=8).grid(row=3,column=1) ttk.Button(plot3, text="Plot 3D", command=self.plot_3d).grid(row=4,column=0, pady=6) ttk.Button(plot3, text="Save PNG", command=self.save_plot).grid(row=4,column=1, pady=6) # Figure fig_frame = ttk.Frame(right); fig_frame.pack(fill="both", expand=True) self.fig = Figure(figsize=(6,5), dpi=110) self.ax = self.fig.add_subplot(111) # will be replaced with 3D when needed self.canvas = FigureCanvasTkAgg(self.fig, master=fig_frame) self.canvas.get_tk_widget().pack(fill="both", expand=True) bottom = ttk.Frame(self); bottom.pack(side="bottom", fill="x", padx=8, pady=6) ttk.Label(bottom, text="برای توابع برداری از np.sin(x), np.cos(...) یا sin(...) استفاده کنید. برای 3D از متغیرهای x و y استفاده کنید.").pack(side="left") # buttons def on_button(self, text): if text == "C": self.expr_var.set("") return if text == "DEL": s = self.expr_var.get(); self.expr_var.set(s[:-1]); return if text == "ans": if self.history: last_ans = self.history[-1][1] self.expr_var.set(self.expr_var.get() + str(last_ans)) return if text == "pi": self.expr_var.set(self.expr_var.get() + "pi"); return if text == "e": self.expr_var.set(self.expr_var.get() + "e"); return if text == "%": self.expr_var.set(self.expr_var.get() + "/100"); return self.expr_var.set(self.expr_var.get() + text) def clear_all(self): self.expr_var.set(""); self.result_var.set(""); self.history.clear(); self.hist_list.delete(0,tk.END); self.clear_plot() def on_history_select(self, event): sel = self.hist_list.curselection() if not sel: return idx = sel[0]; expr, val = self.history[idx] self.expr_var.set(expr); self.result_var.set(str(val)) def evaluate(self): expr = self.expr_var.get().strip() if not expr: return try: val = safe_eval(expr) if isinstance(val, float) and abs(val - round(val)) < 1e-12: val = int(round(val)) self.result_var.set(str(val)) self.history.append((expr, val)); self.hist_list.insert(tk.END, f"{expr} = {val}") except Exception as e: messagebox.showerror("Evaluation error", f"{e}\n\n{traceback.format_exc()}") # plotting 2D def plot_2d(self): expr = self.plot_expr.get().strip() if not expr: messagebox.showwarning("Warning", "عبارت تابع خالی است."); return try: xmin = float(self.xmin_var.get()); xmax = float(self.xmax_var.get()) if xmax <= xmin: raise ValueError("xmax باید بزرگتر از xmin باشد.") samples = int(self.samples_var.get()); samples = max(20, samples) x = np.linspace(xmin, xmax, samples) ef = expr.replace("^", "**") repl_map = ["sin","cos","tan","arcsin","arccos","arctan","sinh","cosh","tanh","exp","log","log10","sqrt","abs"] for fn in repl_map: ef = ef.replace(fn+"(", "np."+fn+"(") local_vars = {"x": x} try: y = safe_eval(ef, local_vars=local_vars) if np.isscalar(y): y = np.full_like(x, float(y), dtype=float) else: y = np.array(y, dtype=float) except Exception: y = [] for xv in x: try: yv = safe_eval(expr, local_vars={"x": float(xv)}); y.append(float(yv)) except Exception: y.append(np.nan) y = np.array(y, dtype=float) self.fig.clf() self.ax = self.fig.add_subplot(111) self.ax.plot(x, y, label=f"f(x)={expr}") self.ax.set_xlim(xmin, xmax); self.ax.grid(True); self.ax.legend() self.canvas.draw() except Exception as e: messagebox.showerror("Plot error", str(e)) # plotting 3D def plot_3d(self): expr = self.plot3_expr.get().strip() if not expr: messagebox.showwarning("Warning", "عبارت تابع خالی است."); return try: xmin = float(self.x3_min.get()); xmax = float(self.x3_max.get()) ymin = float(self.y3_min.get()); ymax = float(self.y3_max.get()) if xmax <= xmin or ymax <= ymin: raise ValueError("حدود x و y نامعتبرند.") samples = int(self.samples3_var.get()); samples = max(10, min(500, samples)) xs = np.linspace(xmin, xmax, samples) ys = np.linspace(ymin, ymax, samples) X, Y = np.meshgrid(xs, ys) # prepare expression for numpy evaluation: replace functions to np.* ef = expr.replace("^", "**") repl_map = ["sin","cos","tan","arcsin","arccos","arctan","sinh","cosh","tanh","exp","log","log10","sqrt","abs"] for fn in repl_map: ef = ef.replace(fn+"(", "np."+fn+"(") local_vars = {"x": X, "y": Y} try: Z = safe_eval(ef, local_vars=local_vars) Z = np.array(Z, dtype=float) except Exception: # fallback pointwise (slower) Z = np.empty_like(X, dtype=float) rows, cols = X.shape for i in range(rows): for j in range(cols): xv = float(X[i,j]); yv = float(Y[i,j]) try: zv = safe_eval(expr, local_vars={"x": xv, "y": yv}) Z[i,j] = float(zv) except Exception: Z[i,j] = np.nan # plot surface self.fig.clf() self.ax = self.fig.add_subplot(111, projection='3d') # choose a colormap and plot_surface surf = self.ax.plot_surface(X, Y, Z, cmap='viridis', linewidth=0, antialiased=True) self.fig.colorbar(surf, ax=self.ax, shrink=0.6) self.ax.set_xlabel('x'); self.ax.set_ylabel('y'); self.ax.set_zlabel('z') self.ax.set_title(f"z = {expr}") self.canvas.draw() except Exception as e: messagebox.showerror("3D Plot error", f"{e}\n\n{traceback.format_exc()}") def save_plot(self): path = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG","*.png")]) if not path: return try: self.fig.savefig(path) messagebox.showinfo("Saved", f"Saved plot to {path}") except Exception as e: messagebox.showerror("Save error", str(e)) def clear_plot(self): self.fig.clf() self.ax = self.fig.add_subplot(111) self.ax.set_title("Plot"); self.ax.grid(True) self.canvas.draw() if __name__ == "__main__": app = ScientificCalculator3D() app.mainloop()
ماشین حسابپایتونپیشرفته
۰
۰
lordtec
lordtec
شاید از این پست‌ها خوشتان بیاید