{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "4ba3c61a-034e-4f09-85b5-33b3071fe265",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 34292 characters]",
      "text/plain": [
       "<Figure size 600x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 37728 characters]",
      "text/plain": [
       "<Figure size 700x350 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 37380 characters]",
      "text/plain": [
       "<Figure size 700x350 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==== Grid ispuna 20.0% ====\n",
      "XY ukupna povrsina     = 31.5777 mm^2\n",
      "  Povrsina ljuski      = 22.8407 mm^2\n",
      "  Povrsina ispune      = 8.7370 mm^2\n",
      "-- Presjeci kroz Z (uzorak konstantan po Z) --\n",
      "Duzina po X @ y=1.000 mm: 2.7234 mm\n",
      "Duzina po Y @ x=-2.000 mm: 2.9837 mm\n",
      "Povrsina XZ @ y=1.000: 13.6170 mm^2  (Z=5.000 mm)\n",
      "Povrsina YZ @ x=-2.000: 14.9186 mm^2  (Z=5.000 mm)\n",
      "\n",
      "A_xz(y=1mm) = 13.617021276595658 mm^2\n",
      "A_yz(x=-2mm) = 14.91864831038789 mm^2\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def _udaljenost_mod(u, razmak):\n",
    "    r = np.mod(u, razmak)\n",
    "    return np.minimum(r, razmak - r)\n",
    "\n",
    "def _pravocrtna_maska(XX, YY, razmak, sirina_linije, kut_stupnjevi=0.0, faza=0.0):\n",
    "\n",
    "    th = np.deg2rad(kut_stupnjevi)\n",
    "    u =  XX * np.cos(th) + YY * np.sin(th)\n",
    "    dist = _udaljenost_mod(u + faza, razmak)\n",
    "    return dist <= (sirina_linije / 2.0)\n",
    "\n",
    "def _razmak_za_gustocu_mreze(sirina_linije, f):\n",
    "\n",
    "    f = float(np.clip(f, 0.0, 1.0))\n",
    "    if f <= 0.0:\n",
    "        return np.inf\n",
    "    if f >= 1.0:\n",
    "        return sirina_linije\n",
    "    r = 1.0 - np.sqrt(1.0 - f)\n",
    "    return sirina_linije / r\n",
    "\n",
    "def izracun_povrsine(XX, YY, maska):\n",
    "    if not np.any(maska):\n",
    "        return {\"A\": 0.0}\n",
    "\n",
    "    dx = XX[0, 1] - XX[0, 0]\n",
    "    dy = YY[1, 0] - YY[0, 0]\n",
    "    dA = dx * dy\n",
    "    A = float(np.count_nonzero(maska) * dA)\n",
    "    return {\"A\": A}\n",
    "\n",
    "def prusa_mreza_ili_pravocrtna(\n",
    "    sirina, visina,\n",
    "    udio_ispune,\n",
    "    sirina_linije=0.42,\n",
    "    slojevi_ljuske=2,\n",
    "    osnovni_kut_ispune_stupnjevi=45.0,\n",
    "    mreza=True,\n",
    "    z_visina=0.0,        \n",
    "    faza_po_mm=0.0,\n",
    "    # Poprecni presjeci kroz Z\n",
    "    z_visina_objekta=None,  \n",
    "    y_ravnina=0.0,          \n",
    "    x_ravnina=0.0,          \n",
    "    N=800,\n",
    "    graficki_prikaz=True,\n",
    "    detaljno=True\n",
    "):\n",
    "    xs = np.linspace(-sirina/2,  sirina/2,  N)\n",
    "    ys = np.linspace(-visina/2, visina/2, N)\n",
    "    XX, YY = np.meshgrid(xs, ys)\n",
    "\n",
    "    shell_mask = np.zeros_like(XX, dtype=bool)\n",
    "    for i in range(slojevi_ljuske):\n",
    "        off = (i + 0.5) * sirina_linije\n",
    "        shell_mask |= np.abs(XX - (-sirina/2  + off)) <= (sirina_linije / 2)\n",
    "        shell_mask |= np.abs(XX - ( +sirina/2  - off)) <= (sirina_linije / 2)\n",
    "        shell_mask |= np.abs(YY - (-visina/2 + off)) <= (sirina_linije / 2)\n",
    "        shell_mask |= np.abs(YY - ( +visina/2 - off)) <= (sirina_linije / 2)\n",
    "\n",
    "    unutarnji_pomak = slojevi_ljuske * sirina_linije\n",
    "    unutarnji_pravokutnik = (\n",
    "        (np.abs(XX) <= (sirina/2  - unutarnji_pomak)) &\n",
    "        (np.abs(YY) <= (visina/2 - unutarnji_pomak))\n",
    "    )\n",
    "\n",
    "    if udio_ispune <= 0.0:\n",
    "        infill_mask = np.zeros_like(XX, dtype=bool)\n",
    "    elif udio_ispune >= 1.0:\n",
    "        razmak = sirina_linije\n",
    "        maske = []\n",
    "        kutevi = [osnovni_kut_ispune_stupnjevi] + ([osnovni_kut_ispune_stupnjevi + 90] if mreza else [])\n",
    "        faza = faza_po_mm * z_visina\n",
    "        for a in kutevi:\n",
    "            maske.append(_pravocrtna_maska(XX, YY, razmak, sirina_linije, kut_stupnjevi=a, faza=faza))\n",
    "        infill_mask = np.logical_or.reduce(maske) & unutarnji_pravokutnik\n",
    "    else:\n",
    "        razmak = _razmak_za_gustocu_mreze(sirina_linije, udio_ispune) if mreza \\\n",
    "                 else sirina_linije / udio_ispune\n",
    "        maske = []\n",
    "        kutevi = [osnovni_kut_ispune_stupnjevi] + ([osnovni_kut_ispune_stupnjevi + 90] if mreza else [])\n",
    "        faza = faza_po_mm * z_visina\n",
    "        for a in kutevi:\n",
    "            maske.append(_pravocrtna_maska(XX, YY, razmak, sirina_linije, kut_stupnjevi=a, faza=faza))\n",
    "        infill_mask = np.logical_or.reduce(maske) & unutarnji_pravokutnik\n",
    "\n",
    "    konacna_maska = shell_mask | infill_mask\n",
    "\n",
    "    if graficki_prikaz:\n",
    "        plt.figure(figsize=(6, 6))\n",
    "        img = np.where(konacna_maska, 1.0, np.nan)\n",
    "        plt.imshow(img, origin='lower',\n",
    "                   extent=[-sirina/2, sirina/2, -visina/2, visina/2],\n",
    "                   interpolation='nearest')\n",
    "        naslov = \"Grid\" if mreza else \"Pravocrtna\"\n",
    "        plt.title(f\"{naslov} @ {udio_ispune*100:.1f}%  | ljuske={slojevi_ljuske}×{sirina_linije:.2f} kut={osnovni_kut_ispune_stupnjevi:.0f}°\")\n",
    "        plt.xlabel(\"X (mm)\")\n",
    "        plt.ylabel(\"Y (mm)\")\n",
    "        plt.gca().set_aspect('equal', 'box')\n",
    "        plt.grid(True)\n",
    "        # vodilice\n",
    "        plt.hlines(y_ravnina, -sirina/2, sirina/2, linestyles='--')\n",
    "        plt.vlines(x_ravnina, -visina/2, visina/2, linestyles='--')\n",
    "        plt.show()\n",
    "\n",
    "    total = izracun_povrsine(XX, YY, konacna_maska)\n",
    "    ljuske = izracun_povrsine(XX, YY, shell_mask)\n",
    "    A_ispuna = total[\"A\"] - ljuske[\"A\"]\n",
    "\n",
    "    dx = XX[0, 1] - XX[0, 0]\n",
    "    dy = YY[1, 0] - YY[0, 0]\n",
    "    ys_centered = YY[:, 0]\n",
    "    xs_centered = XX[0, :]\n",
    "    row = int(np.argmin(np.abs(ys_centered - y_ravnina)))\n",
    "    col = int(np.argmin(np.abs(xs_centered - x_ravnina)))\n",
    "\n",
    "    duzina_x_na_y = float(np.count_nonzero(konacna_maska[row, :]) * dx)\n",
    "    duzina_y_na_x = float(np.count_nonzero(konacna_maska[:, col]) * dy)\n",
    "\n",
    "    povrsina_xz_na_y = None\n",
    "    povrsina_yz_na_x = None\n",
    "    if z_visina_objekta is not None and z_visina_objekta > 0:\n",
    "        povrsina_xz_na_y = duzina_x_na_y * z_visina_objekta\n",
    "        povrsina_yz_na_x = duzina_y_na_x * z_visina_objekta\n",
    "\n",
    "    duzina_x_vs_y = np.count_nonzero(konacna_maska, axis=1) * dx\n",
    "    duzina_y_vs_x = np.count_nonzero(konacna_maska, axis=0) * dy\n",
    "\n",
    "    if z_visina_objekta is not None and z_visina_objekta > 0:\n",
    "        povrsina_xz_vs_y = duzina_x_vs_y * z_visina_objekta\n",
    "        povrsina_yz_vs_x = duzina_y_vs_x * z_visina_objekta\n",
    "        y_oznaka = \"Povrsina XZ presjeka (mm^2)\"\n",
    "        x_oznaka = \"Povrsina YZ presjeka (mm^2)\"\n",
    "    else:\n",
    "        povrsina_xz_vs_y = duzina_x_vs_y\n",
    "        povrsina_yz_vs_x = duzina_y_vs_x\n",
    "        y_oznaka = \"Duzina po X (mm)  [postavi z_visina_objekta za povrsinu]\"\n",
    "        x_oznaka = \"Duzina po Y (mm)  [postavi z_visina_objekta za povrsinu]\"\n",
    "\n",
    "    y_os_0_do_H = ys_centered + visina/2.0\n",
    "    x_os_0_do_W = xs_centered + sirina/2.0\n",
    "\n",
    "    if graficki_prikaz:\n",
    "        plt.figure(figsize=(7, 3.5))\n",
    "        plt.plot(y_os_0_do_H, povrsina_xz_vs_y)\n",
    "        plt.xlabel(\"y od donjeg zida (mm)\")\n",
    "        plt.ylabel(y_oznaka)\n",
    "        plt.title(\"Varijacija prema y\")\n",
    "        plt.grid(True)\n",
    "        plt.xlim(0, visina)\n",
    "        plt.tight_layout()\n",
    "        plt.show()\n",
    "\n",
    "        plt.figure(figsize=(7, 3.5))\n",
    "        plt.plot(x_os_0_do_W, povrsina_yz_vs_x)\n",
    "        plt.xlabel(\"x od lijevog zida (mm)\")\n",
    "        plt.ylabel(x_oznaka)\n",
    "        plt.title(\"Varijacija prema x\")\n",
    "        plt.grid(True)\n",
    "        plt.xlim(0, sirina)\n",
    "        plt.tight_layout()\n",
    "        plt.show()\n",
    "    if detaljno:\n",
    "        print(f\"==== {('Grid' if mreza else 'Pravocrtna')} ispuna {udio_ispune*100:.1f}% ====\")\n",
    "        print(f\"XY ukupna povrsina     = {total['A']:.4f} mm^2\")\n",
    "        print(f\"  Povrsina ljuski      = {ljuske['A']:.4f} mm^2\")\n",
    "        print(f\"  Povrsina ispune      = {A_ispuna:.4f} mm^2\")\n",
    "        print(f\"-- Presjeci kroz Z (uzorak konstantan po Z) --\")\n",
    "        print(f\"Duzina po X @ y={y_ravnina:.3f} mm: {duzina_x_na_y:.4f} mm\")\n",
    "        print(f\"Duzina po Y @ x={x_ravnina:.3f} mm: {duzina_y_na_x:.4f} mm\")\n",
    "        if povrsina_xz_na_y is not None:\n",
    "            print(f\"Povrsina XZ @ y={y_ravnina:.3f}: {povrsina_xz_na_y:.4f} mm^2  (Z={z_visina_objekta:.3f} mm)\")\n",
    "        if povrsina_yz_na_x is not None:\n",
    "            print(f\"Povrsina YZ @ x={x_ravnina:.3f}: {povrsina_yz_na_x:.4f} mm^2  (Z={z_visina_objekta:.3f} mm)\")\n",
    "        print()\n",
    "    return {\n",
    "        \"maska\": konacna_maska,\n",
    "        \"XX\": XX, \"YY\": YY,\n",
    "        \"dx\": dx, \"dy\": dy,\n",
    "        \"povrsina_ukupno_xy\": total[\"A\"],\n",
    "        \"povrsina_ljuske_xy\": ljuske[\"A\"],\n",
    "        \"povrsina_ispune_xy\": A_ispuna,\n",
    "        \"duzina_x_na_y\": duzina_x_na_y,\n",
    "        \"duzina_y_na_x\": duzina_y_na_x,\n",
    "        \"povrsina_xz_na_y\": povrsina_xz_na_y,\n",
    "        \"povrsina_yz_na_x\": povrsina_yz_na_x,\n",
    "        \"y_os_mm\": y_os_0_do_H,\n",
    "        \"x_os_mm\": x_os_0_do_W,\n",
    "        \"povrsina_xz_vs_y\": povrsina_xz_vs_y,\n",
    "        \"povrsina_yz_vs_x\": povrsina_yz_vs_x,\n",
    "    }\n",
    "# Konfiguracija\n",
    "if __name__ == \"__main__\":\n",
    "    W, H = 8.0, 8.0\n",
    "    Z = 5.0 \n",
    "    res = prusa_mreza_ili_pravocrtna(\n",
    "        sirina=W, visina=H,\n",
    "        udio_ispune=0.2,\n",
    "        sirina_linije=0.4,\n",
    "        slojevi_ljuske=2,\n",
    "        osnovni_kut_ispune_stupnjevi=45.0,\n",
    "        mreza=True,\n",
    "        z_visina_objekta=Z,  \n",
    "        y_ravnina=+1.0,     \n",
    "        x_ravnina=-2.0,      \n",
    "        N=800,\n",
    "        graficki_prikaz=True, detaljno=True\n",
    "    )\n",
    "    print(\"A_xz(y=1mm) =\", res[\"povrsina_xz_na_y\"], \"mm^2\")\n",
    "    print(\"A_yz(x=-2mm) =\", res[\"povrsina_yz_na_x\"], \"mm^2\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1975128-5d1b-4522-b686-80d18a7c4fdc",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
