Загрузка данных


<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Лепесток звёздного глобуса — 1000 мм</title>

<style>
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  min-height: 100%;
  background: #e5e5e5;
}

body {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 20px;
  box-sizing: border-box;
}

#download {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 100;
  padding: 10px 16px;
  font-size: 16px;
  cursor: pointer;
}

svg {
  display: block;
  width: min(90vw, 1000px);
  height: auto;
  background: transparent;
}

.grid {
  fill: none;
  stroke: #f0f0f0;
  stroke-width: 0.3;
  vector-effect: non-scaling-stroke;
}

.edge {
  fill: none;
  stroke: #808080;
  stroke-width: 0.5;
  vector-effect: non-scaling-stroke;
}
</style>
</head>

<body>

<button id="download">Скачать SVG</button>

<!--
  Шар диаметром 1000 мм.
  Длина от Северного до Южного полюса
  по поверхности шара = π × 500 = 1570.796 мм.

  Добавлен запас по 10 мм сверху и снизу.
-->
<svg
  id="petal"
  xmlns="http://www.w3.org/2000/svg"
  width="1000mm"
  height="1590mm"
  viewBox="-550 -800 1100 1590"
  preserveAspectRatio="xMidYMin meet">

  <path
    id="petalShape"
    fill="white"
    stroke="none">
  </path>

  <g id="grid"></g>
  <g id="edges"></g>

</svg>

<script>
const svg = document.getElementById("petal");
const grid = document.getElementById("grid");
const edges = document.getElementById("edges");
const petalShape = document.getElementById("petalShape");

const NS = "http://www.w3.org/2000/svg";

const R = 500;

// Один лепесток = 1 час = 15°
const HALF_LON = 7.5;

// --------------------------------------------------
// ПРОЕКЦИЯ
// --------------------------------------------------
//
// Теперь Y — это расстояние по меридиану поверхности шара.
//
// При lat = +90:
// Y = 0
//
// При lat = 0:
// Y = πR/2 = 785.398 мм
//
// При lat = -90:
// Y = πR = 1570.796 мм
//
// Таким образом полная длина лепестка:
// π × 500 = 1570.796 мм
//

function Y(latDeg) {
  const lat = latDeg * Math.PI / 180;

  // Северный полюс = 0
  // Южный полюс = πR
  return R * (Math.PI / 2 - lat);
}

// --------------------------------------------------
// X
// --------------------------------------------------
//
// Ширина лепестка соответствует долготе ±7.5°.
// В экваторе:
// X ≈ ±65.26 мм
//

function X(latDeg, lonDeg) {
  const lat = latDeg * Math.PI / 180;
  const lon = lonDeg * Math.PI / 180;

  return R * Math.sin(lon) * Math.cos(lat);
}

// --------------------------------------------------
// Создание path
// --------------------------------------------------

function makePath(d, cls, parent) {

  const p = document.createElementNS(NS, "path");

  p.setAttribute("d", d);
  p.setAttribute("class", cls);

  parent.appendChild(p);

  return p;
}

// --------------------------------------------------
// БЕЛЫЙ ЛЕПЕСТОК
// --------------------------------------------------

let petalPath = "";

// Левая граница: Северный → Южный полюс
for (let lat = 90; lat >= -90; lat -= 0.5) {

  const x = X(lat, -HALF_LON);
  const y = Y(lat);

  if (lat === 90) {
    petalPath += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
  } else {
    petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
  }
}

// Нижняя точка
{
  const x = X(-90, HALF_LON);
  const y = Y(-90);

  petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}

// Правая граница: Южный → Северный полюс
for (let lat = -89.5; lat <= 90; lat += 0.5) {

  const x = X(lat, HALF_LON);
  const y = Y(lat);

  petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}

petalPath += "Z";

petalShape.setAttribute("d", petalPath);

// --------------------------------------------------
// ПАРАЛЛЕЛИ КАЖДЫЕ 5°
// --------------------------------------------------

for (let lat = -85; lat <= 85; lat += 5) {

  const y = Y(lat);

  const x1 = X(lat, -HALF_LON);
  const x2 = X(lat, HALF_LON);

  makePath(
    `M ${x1.toFixed(4)} ${y.toFixed(4)}
     L ${x2.toFixed(4)} ${y.toFixed(4)}`,
    "grid",
    grid
  );
}

// --------------------------------------------------
// МЕРИДИАН 0°
// --------------------------------------------------

{
  let d = "";

  for (let lat = 90; lat >= -90; lat -= 1) {

    const x = X(lat, 0);
    const y = Y(lat);

    if (lat === 90) {
      d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
    } else {
      d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
    }
  }

  makePath(d, "grid", grid);
}

// --------------------------------------------------
// МЕРИДИАНЫ ±3.75°
// --------------------------------------------------

for (const lon of [-3.75, 3.75]) {

  let d = "";

  for (let lat = 90; lat >= -90; lat -= 1) {

    const x = X(lat, lon);
    const y = Y(lat);

    if (lat === 90) {
      d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
    } else {
      d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
    }
  }

  makePath(d, "grid", grid);
}

// --------------------------------------------------
// КРАЯ ЛЕПЕСТКА
// --------------------------------------------------

for (const lon of [-HALF_LON, HALF_LON]) {

  let d = "";

  for (let lat = 90; lat >= -90; lat -= 0.5) {

    const x = X(lat, lon);
    const y = Y(lat);

    if (lat === 90) {
      d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
    } else {
      d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
    }
  }

  makePath(d, "edge", edges);
}

// --------------------------------------------------
// ПОЛЮСЫ
// --------------------------------------------------

function poleEdge(lat) {

  let d = "";

  for (let i = 0; i <= 30; i++) {

    const lon = -HALF_LON + i * (15 / 30);

    const x = X(lat, lon);
    const y = Y(lat);

    if (i === 0) {
      d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
    } else {
      d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
    }
  }

  makePath(d, "edge", edges);
}

poleEdge(90);
poleEdge(-90);

// --------------------------------------------------
// СКАЧИВАНИЕ SVG
// --------------------------------------------------

document.getElementById("download").addEventListener("click", () => {

  const clone = svg.cloneNode(true);

  // Удаляем кнопку — она не относится к чертежу
  const serializer = new XMLSerializer();

  let source = serializer.serializeToString(clone);

  source =
    '<?xml version="1.0" encoding="UTF-8"?>\n' +
    source;

  const blob = new Blob(
    [source],
    { type: "image/svg+xml;charset=utf-8" }
  );

  const url = URL.createObjectURL(blob);

  const a = document.createElement("a");

  a.href = url;
  a.download = "lepetok_globus_1000mm_diametr_1571mm.svg";

  document.body.appendChild(a);
  a.click();

  document.body.removeChild(a);

  setTimeout(() => {
    URL.revokeObjectURL(url);
  }, 1000);
});
</script>

</body>
</html>