<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>GogoMath - Okręgi i Wielokąty</title>
<style>
  body {
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
  }

  header {
    background: #f5f5f5;
    padding: 10px 20px;
    border-bottom: 1px solid #ccc;
    flex-shrink: 0;
  }

  header h1 {
    margin: 0;
    font-size: 24px;
    color: #333;
    display: inline-block;
    margin-right: 20px;
  }

  nav {
    display: inline-block;
    vertical-align: middle;
  }

  nav button {
    margin: 0 10px;
    background: #eee;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 8px;
    font-size: 14px;
    cursor: pointer;
  }

  nav button.active {
    background: #ddd;
    font-weight: bold;
  }

  main {
    flex: 1;
    display: flex;
    overflow: hidden;
    position: relative;
  }

  .sidebar {
    width: 250px;
    background: #fafafa;
    border-right: 1px solid #ccc;
    padding: 15px;
    display: flex;
    flex-direction: column;
    gap: 15px;
    box-sizing: border-box;
    flex-shrink: 0;
    overflow-y: auto;
  }

  .sidebar h2 {
    font-size: 18px;
    margin: 0;
  }

  .sidebar label {
    font-size: 14px;
    display: flex;
    flex-direction: column;
    margin-bottom: 8px;
    gap:5px;
  }

  .sidebar input[type="number"] {
    padding: 4px;
    box-sizing: border-box;
    width: 100%;
  }

  .sidebar button {
    padding: 8px;
    font-size: 14px;
    cursor: pointer;
    background: #eee;
    border: 1px solid #ccc;
    border-radius: 4px;
  }

  .sidebar button:hover {
    background: #ddd;
  }

  .canvas-container {
    flex: 1;
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #fff;
    overflow: hidden;
  }

  canvas {
    border: 1px solid #ccc;
    background: transparent;
    cursor: grab;
  }

  canvas:active {
    cursor: grabbing;
  }

  footer {
    background: #f5f5f5;
    padding: 5px 20px;
    border-top: 1px solid #ccc;
    font-size: 12px;
    color: #333;
    text-align: right;
    flex-shrink: 0;
  }

  .view {
    display: none;
  }

  .view.active {
    display: flex;
  }

  .info-panel {
    font-size:14px;
    border-top:1px solid #ccc;
    padding-top:10px;
  }

  .info-panel p {
    margin:5px 0;
  }

  .highlight {
    color:#f00; font-weight:bold;
  }

  /* Kontener do zoomu */
  .zoom-container {
    position: absolute;
    bottom: 20px;
    right: 20px;
    background: rgba(255, 255, 255, 0.9);
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    z-index: 10;
  }

  .zoom-container label {
    font-size:14px;
    margin-right:10px;
  }
</style>
</head>
<body>
<header>
  <h1>GogoMath</h1>
  <nav>
    <button class="tabBtn active" data-target="view-circum-triangle">Okrąg opisany (trójkąt)</button>
    <button class="tabBtn" data-target="view-incircle-triangle">Okrąg wpisany (trójkąt)</button>
    <button class="tabBtn" data-target="view-circum-quad">Okrąg opisany (czworokąt)</button>
    <button class="tabBtn" data-target="view-incircle-quad">Okrąg wpisany (czworokąt)</button>
  </nav>
</header>
<main>
  <!-- Okrąg opisany (trójkąt) -->
  <div class="view active" id="view-circum-triangle">
    <div class="sidebar">
      <h2>Okrąg opisany (trójkąt)</h2>
      <label>Punkt A (x1,y1):
        <input type="number" id="x1o" value="100" />
        <input type="number" id="y1o" value="100" />
      </label>
      <label>Punkt B (x2,y2):
        <input type="number" id="x2o" value="200" />
        <input type="number" id="y2o" value="100" />
      </label>
      <label>Punkt C (x3,y3):
        <input type="number" id="x3o" value="150" />
        <input type="number" id="y3o" value="200" />
      </label>
      <label>Szerokość:
        <input type="number" id="canvasWidthO" value="400" min="100" max="2000"/>
      </label>
      <label>Wysokość:
        <input type="number" id="canvasHeightO" value="400" min="100" max="2000"/>
      </label>
      <label><input type="checkbox" id="showLengthsO" checked>Pokaż długości</label>
      <label><input type="checkbox" id="showAnglesO" checked>Pokaż kąty</label>
      <button id="drawBtnO">Rysuj</button>
      <button id="randomBtnO">Losuj</button>
      <button id="downloadBtnO">Pobierz PNG</button>
      <div class="info-panel" id="infoCircumTri"></div>
    </div>
    <div class="canvas-container">
      <canvas id="myCanvasO" width="400" height="400"></canvas>
    </div>
  </div>

  <!-- Okrąg wpisany w trójkąt -->
  <div class="view" id="view-incircle-triangle">
    <div class="sidebar">
      <h2>Okrąg wpisany (trójkąt)</h2>
      <label>Punkt A (x1,y1):
        <input type="number" id="x1i" value="100" />
        <input type="number" id="y1i" value="100" />
      </label>
      <label>Punkt B (x2,y2):
        <input type="number" id="x2i" value="200" />
        <input type="number" id="y2i" value="100" />
      </label>
      <label>Punkt C (x3,y3):
        <input type="number" id="x3i" value="150" />
        <input type="number" id="y3i" value="200" />
      </label>
      <label>Szerokość:
        <input type="number" id="canvasWidthI" value="400" min="100" max="2000"/>
      </label>
      <label>Wysokość:
        <input type="number" id="canvasHeightI" value="400" min="100" max="2000"/>
      </label>
      <label><input type="checkbox" id="showLengthsI" checked>Pokaż długości</label>
      <label><input type="checkbox" id="showAnglesI" checked>Pokaż kąty</label>
      <button id="drawBtnI">Rysuj</button>
      <button id="randomBtnI">Losuj</button>
      <button id="downloadBtnI">Pobierz PNG</button>
      <div class="info-panel" id="infoIncircleTri"></div>
    </div>
    <div class="canvas-container">
      <canvas id="myCanvasI" width="400" height="400"></canvas>
    </div>
  </div>

  <!-- Okrąg opisany na czworokącie -->
  <div class="view" id="view-circum-quad">
    <div class="sidebar">
      <h2>Okrąg opisany (czworokąt)</h2>
      <label>Punkt A (x1,y1):
        <input type="number" id="x1Cq" value="100" />
        <input type="number" id="y1Cq" value="100" />
      </label>
      <label>Punkt B (x2,y2):
        <input type="number" id="x2Cq" value="250" />
        <input type="number" id="y2Cq" value="100" />
      </label>
      <label>Punkt C (x3,y3):
        <input type="number" id="x3Cq" value="300" />
        <input type="number" id="y3Cq" value="200" />
      </label>
      <label>Punkt D (x4,y4):
        <input type="number" id="x4Cq" value="50" />
        <input type="number" id="y4Cq" value="200" />
      </label>
      <label>Szerokość:
        <input type="number" id="canvasWidthCq" value="400" min="100" max="2000"/>
      </label>
      <label>Wysokość:
        <input type="number" id="canvasHeightCq" value="400" min="100" max="2000"/>
      </label>
      <label><input type="checkbox" id="showLengthsCq" checked>Pokaż długości</label>
      <label><input type="checkbox" id="showAnglesCq" checked>Pokaż kąty</label>
      <label><input type="checkbox" id="forceCyclicQuad">Wymuś czworokąt cykliczny</label>
      <button id="drawBtnCq">Rysuj</button>
      <button id="randomBtnCq">Losuj</button>
      <button id="downloadBtnCq">Pobierz PNG</button>
      <div class="info-panel" id="infoCircumQuad"></div>
    </div>
    <div class="canvas-container">
      <canvas id="myCanvasCq" width="400" height="400"></canvas>
    </div>
  </div>

  <!-- Okrąg wpisany w czworokąt -->
  <div class="view" id="view-incircle-quad">
    <div class="sidebar">
      <h2>Okrąg wpisany (czworokąt)</h2>
      <label>Punkt A (x1,y1):
        <input type="number" id="x1Iq" value="120" />
        <input type="number" id="y1Iq" value="100" />
      </label>
      <label>Punkt B (x2,y2):
        <input type="number" id="x2Iq" value="300" />
        <input type="number" id="y2Iq" value="100" />
      </label>
      <label>Punkt C (x3,y3):
        <input type="number" id="x3Iq" value="280" />
        <input type="number" id="y3Iq" value="200" />
      </label>
      <label>Punkt D (x4,y4):
        <input type="number" id="x4Iq" value="140" />
        <input type="number" id="y4Iq" value="200" />
      </label>
      <label>Szerokość:
        <input type="number" id="canvasWidthIq" value="400" min="100" max="2000"/>
      </label>
      <label>Wysokość:
        <input type="number" id="canvasHeightIq" value="400" min="100" max="2000"/>
      </label>
      <label><input type="checkbox" id="showLengthsIq" checked>Pokaż długości</label>
      <label><input type="checkbox" id="showAnglesIq" checked>Pokaż kąty</label>
      <label><input type="checkbox" id="forceTangentialQuad">Wymuś czworokąt tangencjalny (eksperymentalne)</label>
      <button id="drawBtnIq">Rysuj</button>
      <button id="randomBtnIq">Losuj</button>
      <button id="downloadBtnIq">Pobierz PNG</button>
      <div class="info-panel" id="infoIncircleQuad"></div>
    </div>
    <div class="canvas-container">
      <canvas id="myCanvasIq" width="400" height="400"></canvas>
    </div>
  </div>
  
  <!-- Kontener Zoomu -->
  <div class="zoom-container">
    <label>Zoom: <input type="range" min="50" max="300" value="100" id="zoomSlider"></label>
    <span id="zoomValue">100%</span>
  </div>

</main>
<footer>
  Stworzył: Piotr Krzysztof "Meles" Fajkis
</footer>

<script>
// Global transform variables
let scaleFactor = 1.0;
let offsetX = 0;
let offsetY = 0;
let isPanning = false;
let startX = 0;
let startY = 0;
let startOffsetX = 0;
let startOffsetY = 0;

// Zakładki
const tabButtons = document.querySelectorAll('.tabBtn');
const views = document.querySelectorAll('.view');
tabButtons.forEach(btn => {
  btn.addEventListener('click', () => {
    tabButtons.forEach(b => b.classList.remove('active'));
    views.forEach(v => v.classList.remove('active'));
    btn.classList.add('active');
    const targetId = btn.getAttribute('data-target');
    document.getElementById(targetId).classList.add('active');
    resetTransform();
    redrawActiveView();
  });
});

function redrawActiveView() {
  if(document.getElementById('view-circum-triangle').classList.contains('active')) {
    drawTriangleAndCircumcircle();
  } else if(document.getElementById('view-incircle-triangle').classList.contains('active')) {
    drawTriangleAndIncircle();
  } else if(document.getElementById('view-circum-quad').classList.contains('active')) {
    drawQuadCircum();
  } else if(document.getElementById('view-incircle-quad').classList.contains('active')) {
    drawQuadIncircle();
  }
}

function resetTransform() {
  scaleFactor = 1.0;
  offsetX = 0;
  offsetY = 0;
  zoomSlider.value = 100;
  zoomValue.textContent = '100%';
}

// Zoom slider
const zoomSlider = document.getElementById('zoomSlider');
const zoomValue = document.getElementById('zoomValue');

zoomSlider.addEventListener('input', () => {
  scaleFactor = zoomSlider.value / 100;
  zoomValue.textContent = zoomSlider.value + '%';
  redrawActiveView();
});

// Panning functionality
function addPanListeners(canvas) {
  canvas.addEventListener('mousedown', onMouseDown);
  canvas.addEventListener('mousemove', onMouseMove);
  canvas.addEventListener('mouseup', onMouseUp);
  canvas.addEventListener('mouseleave', onMouseUp);
  canvas.addEventListener('wheel', onWheelZoom);
}

function onMouseDown(event) {
  isPanning = true;
  startX = event.clientX;
  startY = event.clientY;
  startOffsetX = offsetX;
  startOffsetY = offsetY;
}

function onMouseMove(event) {
  if (!isPanning) return;
  const dx = event.clientX - startX;
  const dy = event.clientY - startY;
  offsetX = startOffsetX + dx;
  offsetY = startOffsetY + dy;
  redrawActiveView();
}

function onMouseUp(event) {
  isPanning = false;
}

function onWheelZoom(event) {
  event.preventDefault(); // Zapobiega przewijaniu strony

  const canvas = event.currentTarget;
  const rect = canvas.getBoundingClientRect();
  const mouseX = event.clientX - rect.left;
  const mouseY = event.clientY - rect.top;

  // Oblicz pozycję kursora w układzie rysowania
  const x = (mouseX - offsetX) / scaleFactor;
  const y = (mouseY - offsetY) / scaleFactor;

  // Ustal kierunek i krok zoomu
  const delta = event.deltaY < 0 ? 1.1 : 0.9; // Scroll w górę: powiększenie, w dół: pomniejszenie
  const newScaleFactor = scaleFactor * delta;

  // Ustal limity skali
  if (newScaleFactor < 0.5 || newScaleFactor > 3.0) return;

  // Aktualizuj offset, aby zoomować wokół kursora
  offsetX = mouseX - x * newScaleFactor;
  offsetY = mouseY - y * newScaleFactor;

  scaleFactor = newScaleFactor;

  // Aktualizuj suwak zoomu
  zoomSlider.value = scaleFactor * 100;
  zoomValue.textContent = Math.round(scaleFactor * 100) + '%';

  redrawActiveView();
}

// Utility functions
function randomCoord() {
  return Math.floor(Math.random() * 300) + 50; // z zakresu 50-350
}

function dist(x1, y1, x2, y2) {
  return Math.sqrt((x2 - x1)**2 + (y2 - y1)**2);
}

function triangleArea(x1, y1, x2, y2, x3, y3) {
  return Math.abs(x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) / 2;
}

function vectorAngle(xA, yA, xB, yB, xC, yC) {
  const BAx = xA - xB, BAy = yA - yB;
  const BCx = xC - xB, BCy = yC - yB;
  const dot = BAx * BCx + BAy * BCy;
  const magBA = Math.sqrt(BAx**2 + BAy**2);
  const magBC = Math.sqrt(BCx**2 + BCy**2);
  if (magBA === 0 || magBC === 0) return 0;
  let cosTheta = dot / (magBA * magBC);
  if (cosTheta > 1) cosTheta = 1;
  if (cosTheta < -1) cosTheta = -1;
  const angle = Math.acos(cosTheta) * 180 / Math.PI;
  return angle;
}

function drawText(ctx, text, x, y) {
  // Tekst nie skalujemy czcionki, tylko pozycje
  ctx.fillStyle = '#000';
  ctx.font = '14px Arial';
  ctx.fillText(text, x, y);
}

function formatLength(val) {
  const num = parseFloat(val);
  const roundedTwo = Math.round(num * 100) / 100; 
  if (Math.round(roundedTwo) === roundedTwo) {
    return String(Math.round(roundedTwo)); 
  } else {
    const roundedOne = Math.round(num * 10) / 10; 
    return String(roundedOne);
  }
}

function formatAngle(val) {
  const num = parseFloat(val);
  const roundedOne = Math.round(num * 10) / 10;
  return roundedOne.toFixed(1) + "°";
}

function getCircumcircle(x1, y1, x2, y2, x3, y3) {
  const d = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
  if (d === 0) return null;
  const ux = ((x1**2 + y1**2) * (y2 - y3) + (x2**2 + y2**2) * (y3 - y1) + (x3**2 + y3**2) * (y1 - y2)) / d;
  const uy = ((x1**2 + y1**2) * (x3 - x2) + (x2**2 + y2**2) * (x1 - x3) + (x3**2 + y3**2) * (x2 - x1)) / d;
  const r = Math.sqrt((x1 - ux)**2 + (y1 - uy)**2);
  return {cx: ux, cy: uy, r: r};
}

function getIncircleTriangle(x1, y1, x2, y2, x3, y3) {
  const a = dist(x2, y2, x3, y3);
  const b = dist(x1, y1, x3, y3);
  const c = dist(x1, y1, x2, y2);
  const P = a + b + c;
  if (P === 0) return null;
  const ix = (a * x1 + b * x2 + c * x3) / P;
  const iy = (a * y1 + b * y2 + c * y3) / P;
  const A = triangleArea(x1, y1, x2, y2, x3, y3);
  if (A === 0) return null;
  const s = P / 2;
  const r = A / s;
  return {ix, iy, r};
}

function quadArea(x1, y1, x2, y2, x3, y3, x4, y4) {
  const A1 = triangleArea(x1, y1, x2, y2, x3, y3);
  const A2 = triangleArea(x1, y1, x3, y3, x4, y4);
  return A1 + A2;
}

function getIncircleQuadrilateral(x1, y1, x2, y2, x3, y3, x4, y4) {
  const AB = dist(x1, y1, x2, y2);
  const BC = dist(x2, y2, x3, y3);
  const CD = dist(x3, y3, x4, y4);
  const DA = dist(x4, y4, x1, y1);

  if (Math.abs((AB + CD) - (BC + DA)) > 0.0001) return null;
  const P = AB + BC + CD + DA;
  const A = quadArea(x1, y1, x2, y2, x3, y3, x4, y4);
  const r = (2 * A) / P;

  function normalize(vec) {
    const len = Math.sqrt(vec[0]**2 + vec[1]**2);
    if (len > 0) { vec[0] /= len; vec[1] /= len; }
  }

  function angleBisectorIntersection() {
    const u = [x2 - x1, y2 - y1];
    const v = [x4 - x1, y4 - y1];
    normalize(u); normalize(v);
    const bisA = [u[0] + v[0], u[1] + v[1]];
    normalize(bisA);

    const w = [x1 - x2, y1 - y2];
    const z = [x3 - x2, y3 - y2];
    normalize(w); normalize(z);
    const bisB = [w[0] + z[0], w[1] + z[1]];
    normalize(bisB);

    const A_x = x1, A_y = y1;
    const B_x = x2, B_y = y2;
    const a11 = bisA[0], a12 = -bisB[0];
    const a21 = bisA[1], a22 = -bisB[1];
    const b1 = B_x - A_x;
    const b2 = B_y - A_y;

    const det = a11 * a22 - a12 * a21;
    if (Math.abs(det) < 0.000001) return null;
    const t = (b1 * a22 - b2 * a12) / det;
    const ix = A_x + t * bisA[0];
    const iy = A_y + t * bisA[1];
    return [ix, iy];
  }

  const inter = angleBisectorIntersection();
  if (!inter) return null;
  const ix = inter[0], iy = inter[1];
  return {ix, iy, r};
}

// Funkcja pomocnicza do znajdowania punktu D w czworokącie tangencjalnym
function tryTangentialQuad(Ax, Ay, Bx, By, Cx, Cy) {
  const AB = dist(Ax, Ay, Bx, By);
  const BC = dist(Bx, By, Cx, Cy);

  let bestDiff = Infinity;
  let bestD = {x: Ax, y: Ay};
  
  for(let attempt=0; attempt<5; attempt++){
    const angle = Math.random() * 2 * Math.PI;
    const dirX = Math.cos(angle), dirY = Math.sin(angle);
    let left = 10, right = 600; 
    for(let i=0; i<30; i++){
      const mid = (left + right) / 2;
      const Dx = Ax + mid * dirX, Dy = Ay + mid * dirY;
      const CD = dist(Cx, Cy, Dx, Dy);
      const DA = dist(Dx, Dy, Ax, Ay);
      const diff = (AB + CD) - (BC + DA);
      if(Math.abs(diff) < bestDiff){
        bestDiff = Math.abs(diff);
        bestD = {x: Dx, y: Dy};
      }
      if(diff > 0){
        left = mid;
      } else {
        right = mid;
      }
    }
  }
  return bestD;
}

function drawTextFixed(ctx, text, x, y) {
  ctx.fillStyle = '#000';
  ctx.font = '14px Arial';
  ctx.fillText(text, x, y);
}

function drawTriangleLabels(ctx, showLengths, showAngles, x1, y1, x2, y2, x3, y3, AB, BC, CA, angleA, angleB, angleC) {
  const ABf = formatLength(AB);
  const BCf = formatLength(BC);
  const CAf = formatLength(CA);
  
  const angleAf = formatAngle(angleA);
  const angleBf = formatAngle(angleB);
  const angleCf = formatAngle(angleC);

  if(showLengths) {
    drawText(ctx, "AB=" + ABf, (x1 + x2) / 2 * scaleFactor + offsetX, (y1 + y2) / 2 * scaleFactor + offsetY);
    drawText(ctx, "BC=" + BCf, (x2 + x3) / 2 * scaleFactor + offsetX, (y2 + y3) / 2 * scaleFactor + offsetY);
    drawText(ctx, "CA=" + CAf, (x3 + x1) / 2 * scaleFactor + offsetX, (y3 + y1) / 2 * scaleFactor + offsetY);
  }

  if(showAngles) {
    drawText(ctx, "A=" + angleAf, x1 * scaleFactor + offsetX + 10, y1 * scaleFactor + offsetY - 10);
    drawText(ctx, "B=" + angleBf, x2 * scaleFactor + offsetX + 10, y2 * scaleFactor + offsetY - 10);
    drawText(ctx, "C=" + angleCf, x3 * scaleFactor + offsetX + 10, y3 * scaleFactor + offsetY - 10);
  }
}

function drawQuadLabels(ctx, showLengths, showAngles, points, AB, BC, CD, DA, angleA, angleB, angleC, angleD) {
  const A = points[0], B = points[1], C = points[2], D = points[3];

  const ABf = formatLength(AB);
  const BCf = formatLength(BC);
  const CDf = formatLength(CD);
  const DAf = formatLength(DA);

  const angleAf = formatAngle(angleA);
  const angleBf = formatAngle(angleB);
  const angleCf = formatAngle(angleC);
  const angleDf = formatAngle(angleD);

  if(showLengths) {
    drawText(ctx, "AB=" + ABf, (A.x + B.x) / 2 * scaleFactor + offsetX, (A.y + B.y) / 2 * scaleFactor + offsetY);
    drawText(ctx, "BC=" + BCf, (B.x + C.x) / 2 * scaleFactor + offsetX, (B.y + C.y) / 2 * scaleFactor + offsetY);
    drawText(ctx, "CD=" + CDf, (C.x + D.x) / 2 * scaleFactor + offsetX, (C.y + D.y) / 2 * scaleFactor + offsetY);
    drawText(ctx, "DA=" + DAf, (D.x + A.x) / 2 * scaleFactor + offsetX, (D.y + A.y) / 2 * scaleFactor + offsetY);
  }

  if(showAngles) {
    drawText(ctx, "A=" + angleAf, A.x * scaleFactor + offsetX + 10, A.y * scaleFactor + offsetY - 10);
    drawText(ctx, "B=" + angleBf, B.x * scaleFactor + offsetX + 10, B.y * scaleFactor + offsetY - 10);
    drawText(ctx, "C=" + angleCf, C.x * scaleFactor + offsetX + 10, C.y * scaleFactor + offsetY - 10);
    drawText(ctx, "D=" + angleDf, D.x * scaleFactor + offsetX + 10, D.y * scaleFactor + offsetY - 10);
  }
}

function drawQuadrilateral(ctx, points, strokeStyle = '#000') {
  ctx.strokeStyle = strokeStyle; 
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.moveTo(points[0].x * scaleFactor + offsetX, points[0].y * scaleFactor + offsetY);
  for(let i = 1; i < points.length; i++) {
    ctx.lineTo(points[i].x * scaleFactor + offsetX, points[i].y * scaleFactor + offsetY);
  }
  ctx.closePath();
  ctx.stroke();
}

function downloadPNG(canvas, filename) {
  const dataURL = canvas.toDataURL('image/png');
  const a = document.createElement('a');
  a.href = dataURL;
  a.download = filename;
  a.click();
}

// --- Okrąg opisany (trójkąt) ---
const x1o = document.getElementById('x1o');
const y1o = document.getElementById('y1o');
const x2o = document.getElementById('x2o');
const y2o = document.getElementById('y2o');
const x3o = document.getElementById('x3o');
const y3o = document.getElementById('y3o');
const canvasWidthO = document.getElementById('canvasWidthO');
const canvasHeightO = document.getElementById('canvasHeightO');
const showLengthsO = document.getElementById('showLengthsO');
const showAnglesO = document.getElementById('showAnglesO');
const drawBtnO = document.getElementById('drawBtnO');
const downloadBtnO = document.getElementById('downloadBtnO');
const randomBtnO = document.getElementById('randomBtnO');
const canvasO = document.getElementById('myCanvasO');
const ctxO = canvasO.getContext('2d');
const infoCircumTri = document.getElementById('infoCircumTri');

addPanListeners(canvasO);

function drawTriangleAndCircumcircle() {
  const x1 = parseFloat(x1o.value), y1 = parseFloat(y1o.value);
  const x2 = parseFloat(x2o.value), y2 = parseFloat(y2o.value);
  const x3 = parseFloat(x3o.value), y3 = parseFloat(y3o.value);
  const w = parseInt(canvasWidthO.value, 10), h = parseInt(canvasHeightO.value, 10);

  canvasO.width = w;
  canvasO.height = h;
  ctxO.clearRect(0, 0, w, h);

  // Trójkąt
  ctxO.strokeStyle = '#000';
  ctxO.lineWidth = 2;
  ctxO.beginPath();
  ctxO.moveTo(x1 * scaleFactor + offsetX, y1 * scaleFactor + offsetY);
  ctxO.lineTo(x2 * scaleFactor + offsetX, y2 * scaleFactor + offsetY);
  ctxO.lineTo(x3 * scaleFactor + offsetX, y3 * scaleFactor + offsetY);
  ctxO.closePath();
  ctxO.stroke();

  const circ = getCircumcircle(x1, y1, x2, y2, x3, y3);

  const AB = dist(x1, y1, x2, y2);
  const BC = dist(x2, y2, x3, y3);
  const CA = dist(x3, y3, x1, y1);

  const angleA = vectorAngle(x3, y3, x1, y1, x2, y2);
  const angleB = vectorAngle(x1, y1, x2, y2, x3, y3);
  const angleC = vectorAngle(x2, y2, x3, y3, x1, y1);

  let msg = '';
  if(circ) {
    ctxO.strokeStyle = '#f00';
    ctxO.beginPath();
    ctxO.arc(circ.cx * scaleFactor + offsetX, circ.cy * scaleFactor + offsetY, circ.r * scaleFactor, 0, 2 * Math.PI);
    ctxO.stroke();
    ctxO.fillStyle = '#00f';
    ctxO.beginPath();
    ctxO.arc(circ.cx * scaleFactor + offsetX, circ.cy * scaleFactor + offsetY, 3, 0, 2 * Math.PI);
    ctxO.fill();
    msg = '<p>Okrąg opisany narysowany.</p>';
  } else {
    msg = '<p class="highlight">Punkty współliniowe lub brak okręgu opisanego.</p>';
  }

  drawTriangleLabels(ctxO, showLengthsO.checked, showAnglesO.checked, x1, y1, x2, y2, x3, y3, AB, BC, CA, angleA, angleB, angleC);

  infoCircumTri.innerHTML = `<p><b>Boki:</b><br>AB=${formatLength(AB)}, BC=${formatLength(BC)}, CA=${formatLength(CA)}</p>
  <p><b>Kąty (°):</b><br>A=${formatAngle(angleA)}, B=${formatAngle(angleB)}, C=${formatAngle(angleC)}</p>${msg}`;
}

function downloadPNGO() {
  downloadPNG(canvasO, 'gogomath_okrag_opisany_trojkat.png');
}

function randomTriangleCircum() {
  x1o.value = randomCoord(); y1o.value = randomCoord();
  x2o.value = randomCoord(); y2o.value = randomCoord();
  x3o.value = randomCoord(); y3o.value = randomCoord();
  drawTriangleAndCircumcircle();
}

drawBtnO.addEventListener('click', drawTriangleAndCircumcircle);
randomBtnO.addEventListener('click', randomTriangleCircum);
downloadBtnO.addEventListener('click', downloadPNGO);
drawTriangleAndCircumcircle();

// --- Okrąg wpisany (trójkąt) ---
const x1i = document.getElementById('x1i');
const y1i = document.getElementById('y1i');
const x2i = document.getElementById('x2i');
const y2i = document.getElementById('y2i');
const x3i = document.getElementById('x3i');
const y3i = document.getElementById('y3i');
const canvasWidthI = document.getElementById('canvasWidthI');
const canvasHeightI = document.getElementById('canvasHeightI');
const showLengthsI = document.getElementById('showLengthsI');
const showAnglesI = document.getElementById('showAnglesI');
const drawBtnI = document.getElementById('drawBtnI');
const downloadBtnI = document.getElementById('downloadBtnI');
const randomBtnI = document.getElementById('randomBtnI');
const canvasI = document.getElementById('myCanvasI');
const ctxI = canvasI.getContext('2d');
const infoIncircleTri = document.getElementById('infoIncircleTri');

addPanListeners(canvasI);

function getIncircleQuadrilateral(x1, y1, x2, y2, x3, y3, x4, y4) {
  const AB = dist(x1, y1, x2, y2);
  const BC = dist(x2, y2, x3, y3);
  const CD = dist(x3, y3, x4, y4);
  const DA = dist(x4, y4, x1, y1);

  if (Math.abs((AB + CD) - (BC + DA)) > 0.0001) return null;
  const P = AB + BC + CD + DA;
  const A = quadArea(x1, y1, x2, y2, x3, y3, x4, y4);
  const r = (2 * A) / P;

  function normalize(vec) {
    const len = Math.sqrt(vec[0]**2 + vec[1]**2);
    if (len > 0) { vec[0] /= len; vec[1] /= len; }
  }

  function angleBisectorIntersection() {
    const u = [x2 - x1, y2 - y1];
    const v = [x4 - x1, y4 - y1];
    normalize(u); normalize(v);
    const bisA = [u[0] + v[0], u[1] + v[1]];
    normalize(bisA);

    const w = [x1 - x2, y1 - y2];
    const z = [x3 - x2, y3 - y2];
    normalize(w); normalize(z);
    const bisB = [w[0] + z[0], w[1] + z[1]];
    normalize(bisB);

    const A_x = x1, A_y = y1;
    const B_x = x2, B_y = y2;
    const a11 = bisA[0], a12 = -bisB[0];
    const a21 = bisA[1], a22 = -bisB[1];
    const b1 = B_x - A_x;
    const b2 = B_y - A_y;

    const det = a11 * a22 - a12 * a21;
    if (Math.abs(det) < 0.000001) return null;
    const t = (b1 * a22 - b2 * a12) / det;
    const ix = A_x + t * bisA[0];
    const iy = A_y + t * bisA[1];
    return [ix, iy];
  }

  const inter = angleBisectorIntersection();
  if (!inter) return null;
  const ix = inter[0], iy = inter[1];
  return {ix, iy, r};
}

function drawTriangleAndIncircle() {
  const x1 = parseFloat(x1i.value), y1 = parseFloat(y1i.value);
  const x2 = parseFloat(x2i.value), y2 = parseFloat(y2i.value);
  const x3 = parseFloat(x3i.value), y3 = parseFloat(y3i.value);
  const w = parseInt(canvasWidthI.value, 10), h = parseInt(canvasHeightI.value, 10);

  canvasI.width = w; 
  canvasI.height = h;
  ctxI.clearRect(0, 0, w, h);

  ctxI.strokeStyle = '#000'; 
  ctxI.lineWidth = 2;
  ctxI.beginPath();
  ctxI.moveTo(x1 * scaleFactor + offsetX, y1 * scaleFactor + offsetY);
  ctxI.lineTo(x2 * scaleFactor + offsetX, y2 * scaleFactor + offsetY);
  ctxI.lineTo(x3 * scaleFactor + offsetX, y3 * scaleFactor + offsetY);
  ctxI.closePath();
  ctxI.stroke();

  const inc = getIncircleTriangle(x1, y1, x2, y2, x3, y3);

  const AB = dist(x1, y1, x2, y2);
  const BC = dist(x2, y2, x3, y3);
  const CA = dist(x3, y3, x1, y1);

  const angleA = vectorAngle(x3, y3, x1, y1, x2, y2);
  const angleB = vectorAngle(x1, y1, x2, y2, x3, y3);
  const angleC = vectorAngle(x2, y2, x3, y3, x1, y1);

  let msg = '';
  if(inc) {
    ctxI.strokeStyle = '#f00';
    ctxI.beginPath();
    ctxI.arc(inc.ix * scaleFactor + offsetX, inc.iy * scaleFactor + offsetY, inc.r * scaleFactor, 0, 2 * Math.PI);
    ctxI.stroke();
    ctxI.fillStyle = '#00f';
    ctxI.beginPath();
    ctxI.arc(inc.ix * scaleFactor + offsetX, inc.iy * scaleFactor + offsetY, 3, 0, 2 * Math.PI);
    ctxI.fill();
    msg = '<p>Okrąg wpisany narysowany.</p>';
  } else {
    msg = '<p class="highlight">Brak okręgu wpisanego (degeneracja).</p>';
  }

  drawTriangleLabels(ctxI, showLengthsI.checked, showAnglesI.checked, x1, y1, x2, y2, x3, y3, AB, BC, CA, angleA, angleB, angleC);

  infoIncircleTri.innerHTML = `<p><b>Boki:</b><br>AB=${formatLength(AB)}, BC=${formatLength(BC)}, CA=${formatLength(CA)}</p>
  <p><b>Kąty (°):</b><br>A=${formatAngle(angleA)}, B=${formatAngle(angleB)}, C=${formatAngle(angleC)}</p>${msg}`;
}

function downloadPNGI() {
  downloadPNG(canvasI, 'gogomath_okrag_wpisany_trojkat.png');
}

function randomTriangleIncircle() {
  x1i.value = randomCoord(); y1i.value = randomCoord();
  x2i.value = randomCoord(); y2i.value = randomCoord();
  x3i.value = randomCoord(); y3i.value = randomCoord();
  drawTriangleAndIncircle();
}

drawBtnI.addEventListener('click', drawTriangleAndIncircle);
randomBtnI.addEventListener('click', randomTriangleIncircle);
downloadBtnI.addEventListener('click', downloadPNGI);
drawTriangleAndIncircle();

// --- Okrąg opisany (czworokąt) ---
const x1Cq = document.getElementById('x1Cq');
const y1Cq = document.getElementById('y1Cq');
const x2Cq = document.getElementById('x2Cq');
const y2Cq = document.getElementById('y2Cq');
const x3Cq = document.getElementById('x3Cq');
const y3Cq = document.getElementById('y3Cq');
const x4Cq = document.getElementById('x4Cq');
const y4Cq = document.getElementById('y4Cq');
const canvasWidthCq = document.getElementById('canvasWidthCq');
const canvasHeightCq = document.getElementById('canvasHeightCq');
const showLengthsCq = document.getElementById('showLengthsCq');
const showAnglesCq = document.getElementById('showAnglesCq');
const forceCyclicQuad = document.getElementById('forceCyclicQuad');
const drawBtnCq = document.getElementById('drawBtnCq');
const downloadBtnCq = document.getElementById('downloadBtnCq');
const randomBtnCq = document.getElementById('randomBtnCq');
const canvasCq = document.getElementById('myCanvasCq');
const ctxCq = canvasCq.getContext('2d');
const infoCircumQuad = document.getElementById('infoCircumQuad');

addPanListeners(canvasCq);

function drawQuadCircum() {
  const x1 = parseFloat(x1Cq.value), y1 = parseFloat(y1Cq.value);
  const x2 = parseFloat(x2Cq.value), y2 = parseFloat(y2Cq.value);
  const x3 = parseFloat(x3Cq.value), y3 = parseFloat(y3Cq.value);
  const x4 = parseFloat(x4Cq.value), y4 = parseFloat(y4Cq.value);

  const w = parseInt(canvasWidthCq.value, 10), h = parseInt(canvasHeightCq.value, 10);
  canvasCq.width = w; 
  canvasCq.height = h;
  ctxCq.clearRect(0, 0, w, h);

  const points = [{x: x1, y: y1}, {x: x2, y: y2}, {x: x3, y: y3}, {x: x4, y: y4}];
  drawQuadrilateral(ctxCq, points);

  const AB = dist(x1, y1, x2, y2);
  const BC = dist(x2, y2, x3, y3);
  const CD = dist(x3, y3, x4, y4);
  const DA = dist(x4, y4, x1, y1);

  const angleA = vectorAngle(x4, y4, x1, y1, x2, y2);
  const angleB = vectorAngle(x1, y1, x2, y2, x3, y3);
  const angleC = vectorAngle(x2, y2, x3, y3, x4, y4);
  const angleD = vectorAngle(x3, y3, x4, y4, x1, y1);

  const circ = getCircumcircle(x1, y1, x2, y2, x3, y3);
  let cyclicMsg = '';
  if(circ) {
    const distD = Math.sqrt((x4 - circ.cx)**2 + (y4 - circ.cy)**2);
    if(Math.abs(distD - circ.r) < 0.0001) {
      ctxCq.strokeStyle = '#f00';
      ctxCq.beginPath();
      ctxCq.arc(circ.cx * scaleFactor + offsetX, circ.cy * scaleFactor + offsetY, circ.r * scaleFactor, 0, 2 * Math.PI);
      ctxCq.stroke();
      ctxCq.fillStyle = '#00f';
      ctxCq.beginPath();
      ctxCq.arc(circ.cx * scaleFactor + offsetX, circ.cy * scaleFactor + offsetY, 3, 0, 2 * Math.PI);
      ctxCq.fill();

      const sumAC = (angleA + angleC).toFixed(2);
      const sumBD = (angleB + angleD).toFixed(2);
      cyclicMsg = `<p class="highlight">Czworokąt jest cykliczny</p>
      <p>Suma kątów A+C = ${formatAngle(sumAC)}, B+D = ${formatAngle(sumBD)} (~180°)</p>`;
    } else {
      cyclicMsg = `<p class="highlight">Czworokąt nie jest cykliczny</p>`;
    }
  } else {
    cyclicMsg = `<p class="highlight">Brak okręgu (A,B,C współliniowe)</p>`;
  }

  drawQuadLabels(ctxCq, showLengthsCq.checked, showAnglesCq.checked, points, AB, BC, CD, DA, angleA, angleB, angleC, angleD);

  infoCircumQuad.innerHTML = `<p><b>Boki:</b><br>AB=${formatLength(AB)}, BC=${formatLength(BC)}, CD=${formatLength(CD)}, DA=${formatLength(DA)}</p>
  <p><b>Kąty (°):</b><br>A=${formatAngle(angleA)}, B=${formatAngle(angleB)}, C=${formatAngle(angleC)}, D=${formatAngle(angleD)}</p>${cyclicMsg}`;
}

function randomQuadCircum() {
  if (forceCyclicQuad.checked) {
    let ax = randomCoord(), ay = randomCoord();
    let bx = randomCoord(), by = randomCoord();
    let cx = randomCoord(), cy = randomCoord();

    let circ = getCircumcircle(ax, ay, bx, by, cx, cy);
    let attempts = 0;
    while(!circ && attempts < 100) {
      ax = randomCoord(); ay = randomCoord();
      bx = randomCoord(); by = randomCoord();
      cx = randomCoord(); cy = randomCoord();
      circ = getCircumcircle(ax, ay, bx, by, cx, cy);
      attempts++;
    }

    if(!circ) {
      x1Cq.value = randomCoord(); y1Cq.value = randomCoord();
      x2Cq.value = randomCoord(); y2Cq.value = randomCoord();
      x3Cq.value = randomCoord(); y3Cq.value = randomCoord();
      x4Cq.value = randomCoord(); y4Cq.value = randomCoord();
    } else {
      const theta = Math.random() * 2 * Math.PI;
      const dx = circ.cx + circ.r * Math.cos(theta);
      const dy = circ.cy + circ.r * Math.sin(theta);

      x1Cq.value = ax; y1Cq.value = ay;
      x2Cq.value = bx; y2Cq.value = by;
      x3Cq.value = cx; y3Cq.value = cy;
      x4Cq.value = dx; y4Cq.value = dy;
    }

  } else {
    x1Cq.value = randomCoord(); y1Cq.value = randomCoord();
    x2Cq.value = randomCoord(); y2Cq.value = randomCoord();
    x3Cq.value = randomCoord(); y3Cq.value = randomCoord();
    x4Cq.value = randomCoord(); y4Cq.value = randomCoord();
  }
  drawQuadCircum();
}

function downloadPNGCq() {
  downloadPNG(canvasCq, 'gogomath_okrag_opisany_czworokat.png');
}

drawBtnCq.addEventListener('click', drawQuadCircum);
randomBtnCq.addEventListener('click', randomQuadCircum);
downloadBtnCq.addEventListener('click', downloadPNGCq);
drawQuadCircum();

// --- Okrąg wpisany (czworokąt) ---
const x1Iq = document.getElementById('x1Iq');
const y1Iq = document.getElementById('y1Iq');
const x2Iq = document.getElementById('x2Iq');
const y2Iq = document.getElementById('y2Iq');
const x3Iq = document.getElementById('x3Iq');
const y3Iq = document.getElementById('y3Iq');
const x4Iq = document.getElementById('x4Iq');
const y4Iq = document.getElementById('y4Iq');
const canvasWidthIq = document.getElementById('canvasWidthIq');
const canvasHeightIq = document.getElementById('canvasHeightIq');
const showLengthsIq = document.getElementById('showLengthsIq');
const showAnglesIq = document.getElementById('showAnglesIq');
const forceTangentialQuad = document.getElementById('forceTangentialQuad');
const drawBtnIq = document.getElementById('drawBtnIq');
const downloadBtnIq = document.getElementById('downloadBtnIq');
const randomBtnIq = document.getElementById('randomBtnIq');
const canvasIq = document.getElementById('myCanvasIq');
const ctxIq = canvasIq.getContext('2d');
const infoIncircleQuad = document.getElementById('infoIncircleQuad');

addPanListeners(canvasIq);

function drawQuadIncircle() {
  const x1 = parseFloat(x1Iq.value), y1 = parseFloat(y1Iq.value);
  const x2 = parseFloat(x2Iq.value), y2 = parseFloat(y2Iq.value);
  const x3 = parseFloat(x3Iq.value), y3 = parseFloat(y3Iq.value);
  const x4 = parseFloat(x4Iq.value), y4 = parseFloat(y4Iq.value);

  const w = parseInt(canvasWidthIq.value, 10), h = parseInt(canvasHeightIq.value, 10);
  canvasIq.width = w;
  canvasIq.height = h;
  ctxIq.clearRect(0, 0, w, h);

  const points = [{x: x1, y: y1}, {x: x2, y: y2}, {x: x3, y: y3}, {x: x4, y: y4}];
  drawQuadrilateral(ctxIq, points);

  const AB = dist(x1, y1, x2, y2);
  const BC = dist(x2, y2, x3, y3);
  const CD = dist(x3, y3, x4, y4);
  const DA = dist(x4, y4, x1, y1);

  const angleA = vectorAngle(x4, y4, x1, y1, x2, y2);
  const angleB = vectorAngle(x1, y1, x2, y2, x3, y3);
  const angleC = vectorAngle(x2, y2, x3, y3, x4, y4);
  const angleD = vectorAngle(x3, y3, x4, y4, x1, y1);

  const incq = getIncircleQuadrilateral(x1, y1, x2, y2, x3, y3, x4, y4);
  const sum1 = (AB + CD).toFixed(2);
  const sum2 = (BC + DA).toFixed(2);
  let incircleMsg = '';

  if(incq) {
    ctxIq.strokeStyle = '#f00';
    ctxIq.beginPath();
    ctxIq.arc(incq.ix * scaleFactor + offsetX, incq.iy * scaleFactor + offsetY, incq.r * scaleFactor, 0, 2 * Math.PI);
    ctxIq.stroke();
    ctxIq.fillStyle = '#00f';
    ctxIq.beginPath();
    ctxIq.arc(incq.ix * scaleFactor + offsetX, incq.iy * scaleFactor + offsetY, 3, 0, 2 * Math.PI);
    ctxIq.fill();
    incircleMsg = `<p class="highlight">Czworokąt jest tangencjalny (okrąg wpisany istnieje).</p>
    <p>AB+CD = ${formatLength(sum1)}, BC+DA = ${formatLength(sum2)} (równe sumy)</p>`;
  } else {
    incircleMsg = `<p class="highlight">Czworokąt nie jest tangencjalny - brak okręgu wpisanego.</p>
    <p>AB+CD = ${formatLength(sum1)}, BC+DA = ${formatLength(sum2)} (brak równości)</p>`;
  }

  drawQuadLabels(ctxIq, showLengthsIq.checked, showAnglesIq.checked, points, AB, BC, CD, DA, angleA, angleB, angleC, angleD);

  infoIncircleQuad.innerHTML = `<p><b>Boki:</b><br>AB=${formatLength(AB)}, BC=${formatLength(BC)}, CD=${formatLength(CD)}, DA=${formatLength(DA)}</p>
  <p><b>Kąty (°):</b><br>A=${formatAngle(angleA)}, B=${formatAngle(angleB)}, C=${formatAngle(angleC)}, D=${formatAngle(angleD)}</p>${incircleMsg}`;
}

function randomQuadIncircle() {
  if(forceTangentialQuad.checked) {
    const Ax = randomCoord(), Ay = randomCoord();
    const Bx = randomCoord(), By = randomCoord();
    const Cx = randomCoord(), Cy = randomCoord();

    const D = tryTangentialQuad(Ax, Ay, Bx, By, Cx, Cy);

    x1Iq.value = Ax; y1Iq.value = Ay;
    x2Iq.value = Bx; y2Iq.value = By;
    x3Iq.value = Cx; y3Iq.value = Cy;
    x4Iq.value = D.x; y4Iq.value = D.y;

  } else {
    x1Iq.value = randomCoord(); y1Iq.value = randomCoord();
    x2Iq.value = randomCoord(); y2Iq.value = randomCoord();
    x3Iq.value = randomCoord(); y3Iq.value = randomCoord();
    x4Iq.value = randomCoord(); y4Iq.value = randomCoord();
  }
  drawQuadIncircle();
}

function downloadPNGIq() {
  downloadPNG(canvasIq, 'gogomath_okrag_wpisany_czworokat.png');
}

drawBtnIq.addEventListener('click', drawQuadIncircle);
randomBtnIq.addEventListener('click', randomQuadIncircle);
downloadBtnIq.addEventListener('click', downloadPNGIq);
drawQuadIncircle();
</script>
</body>
</html>
