<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Майор Котик</title><generator>teletype.in</generator><description><![CDATA[Фронтендер с лапками 🐾 
Работаю с гео данными 📊
Несу картографию в массы 🗺️]]></description><image><url>https://img1.teletype.in/files/c4/1c/c41c2bee-7d89-4e8b-8e06-418eebdcb137.png</url><title>Майор Котик</title><link>https://teletype.in/@rellowy</link></image><link>https://teletype.in/@rellowy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/rellowy?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/rellowy?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Sat, 11 Apr 2026 14:43:02 GMT</pubDate><lastBuildDate>Sat, 11 Apr 2026 14:43:02 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@rellowy/create-osm-layers</guid><link>https://teletype.in/@rellowy/create-osm-layers?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><comments>https://teletype.in/@rellowy/create-osm-layers?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy#comments</comments><dc:creator>rellowy</dc:creator><title>Создание слоя: загрузка данных</title><pubDate>Sun, 05 May 2024 19:37:43 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/f9/4c/f94c4cb6-14f4-4635-b8d3-9145c2ad36e2.png"></media:content><description><![CDATA[<img src="https://img4.teletype.in/files/74/bd/74bd0299-4ef8-4c68-820f-a01ac1c06382.png"></img>Загружаем OSM в БД Postgres!]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="z2V4">В прошлом уроке мы с вами поднимали данных Postgres в контейнере. Если вы забыли или пропустили, рекомендую <a href="https://teletype.in/@rellowy/postgres-in-docker" target="_blank">вернуться</a> и освежить знания.</p>
  </section>
  <hr />
  <p id="321v">Мы с вами уже знаем, что для создания слоя необходимо иметь геометрию.</p>
  <blockquote id="RF1s">Но у нас же ничего нет... Где нам ее взять??</blockquote>
  <p id="wK98">И на такой вопрос есть решение. Мы с вами рассмотрим самую популярную задачу - загрузку OpenStreetMap (OSM) в свою базу с дальнейшим выводом на карту. </p>
  <hr />
  <h2 id="ULgE">Что нам потребуется?</h2>
  <h3 id="2c9M">Подготовка базы данных</h3>
  <p id="Plpt">Первое, что нам необходимо сделать - создать отдельную базу данных с отдельным пользователем, чтобы отделить OSM от всех остальных данных. </p>
  <p id="PpfJ">На прошлом занятии мы уже подключились к базе данных с помощью pgAdmin. С этого места и продолжим наш путь <s>джедая</s> котика.</p>
  <p id="GLoH"><strong>Создаем нового пользователя</strong></p>
  <ol id="rdOJ">
    <li id="Tis9">Открываем наш сервер и кликаем ПКМ по Login/Group roles =&gt; Create =&gt; Login/Group Role... (рис 1.)</li>
    <li id="FwJd">Указываем имя нашего пользователя. У меня это будет <strong>osm </strong>(Рис 2.)</li>
    <li id="3Txk">На вкладке <strong>Definition </strong>указываем пароль и не забываем его запомнить/записать (Рис 3.)</li>
    <li id="fiA1">На вкладке <strong>Privileges</strong> ставим ползунок напротив <strong>Can login </strong>(Рис 4.)</li>
  </ol>
  <figure id="ciyi" class="m_custom">
    <img src="https://img2.teletype.in/files/57/74/5774a5b4-a10c-4b5c-bbe7-2cd4c67652bf.png" width="663" />
    <figcaption>Рис 1. Меню создания нового пользователя</figcaption>
  </figure>
  <figure id="Fx0R" class="m_original">
    <img src="https://img3.teletype.in/files/ef/84/ef84fe80-ee9d-4234-93f1-ed8c969b8b16.png" width="818" />
    <figcaption>Рис 2. Вводим имя пользователя</figcaption>
  </figure>
  <figure id="IbIJ" class="m_original">
    <img src="https://img2.teletype.in/files/55/d3/55d32528-19dc-429c-9c83-ab08030010b7.png" width="818" />
    <figcaption>Рис 3. Указываем пароль</figcaption>
  </figure>
  <figure id="lJsB" class="m_original">
    <img src="https://img3.teletype.in/files/20/bf/20bf10c2-2532-4e73-ae51-8846c9b7f38a.png" width="817" />
    <figcaption>Рис 4. Даем права</figcaption>
  </figure>
  <p id="v9lh"></p>
  <p id="pSrw"><strong>Создаем базу данных</strong></p>
  <p id="CNms">Теперь пришло время создавать наше хранилище данных.</p>
  <ol id="iDTL">
    <li id="LqDs">Кликаем ПКМ по Databases <strong>(Рис 5.)</strong></li>
    <li id="zdXB">Указываем основные параметры <strong>(Рис 6.)</strong></li>
    <ol id="oeJy">
      <li id="00O2">Имя базы данных - у меня это <strong>osm</strong></li>
      <li id="Nrf2">Owner - владельцем нашей базы ставим созданного пользователя</li>
    </ol>
    <li id="Ocnz">Для работы с геометрией обязательно необходимо поставить расширение postgis </li>
    <ol id="21Z2">
      <li id="kxTj">Раскрываем нашу базу</li>
      <li id="1efh">Кликаем ПКМ по Extensions =&gt; Create =&gt; Extension... <strong>(Рис 7.)</strong></li>
      <li id="1EpJ">В списке наименований выбираем posgis <strong>(Рис. 8)</strong></li>
    </ol>
  </ol>
  <figure id="aY89" class="m_original">
    <img src="https://img3.teletype.in/files/2c/b2/2cb27d9e-63dd-48c0-ab9b-d296b28ea977.png" width="628" />
    <figcaption>Рис 5. Вызов меню создания базы</figcaption>
  </figure>
  <figure id="jo7X" class="m_original">
    <img src="https://img4.teletype.in/files/37/30/3730d289-6ae1-4273-8f75-5ffe668d1466.png" width="695" />
    <figcaption>Рис 6. Установка основных параметров</figcaption>
  </figure>
  <figure id="Gphn" class="m_original">
    <img src="https://img1.teletype.in/files/8d/22/8d22d941-413b-442f-9dfa-4a942f6dd350.png" width="571" />
    <figcaption>Рис. 7 Вызов меню добавления расширения</figcaption>
  </figure>
  <figure id="O1gP" class="m_original">
    <img src="https://img4.teletype.in/files/72/62/7262cf19-abbf-4043-91e2-ca3146990646.png" width="497" />
    <figcaption>Рис 8. Добавляем расширение postgis</figcaption>
  </figure>
  <hr />
  <blockquote id="aYL7">Котик, база готова. Что же дальше? </blockquote>
  <p id="3LuL">А дальше мы будем заливать данные! </p>
  <hr />
  <p id="C6WF">Первое, что нам потребуется - скрипты для загрузки и файл. Я уже подготовил загрузчик. Сегодня мы посмотрим, как же его использовать.</p>
  <p id="hnV7">Загрузчик сделан на базе утилиты osm2pgsql. Что же это за штука такая чудесная? Osm2pgsql позволяет без особых усилий и больших страданий загружать данные OSM в базу postgres.</p>
  <p id="060s">А теперь поехали загружать.</p>
  <p id="1lXN">Нам необходимо склонировать <a href="https://github.com/rellowy/gis/" target="_blank">репозиторий</a> в любую удобную папку.</p>
  <p id="SxFa">Далее необходимо собрать docker образ, в котором установлен osm2pgsql. Для этого необходимо выполнить команду и дождаться окончания.</p>
  <pre id="LIMT" data-lang="bash">cd ./osm2pgsql &amp;&amp; docker build -t osm2pgsql:latest .</pre>
  <p id="UTj3"><br />Теперь нам необходимо скачать файл с данными. Переходим на <a href="https://download.geofabrik.de/russia.html" target="_blank">сайт</a> и качаем russia-latest.osm.pbf.</p>
  <figure id="SnxF" class="m_custom">
    <img src="https://img4.teletype.in/files/f0/ca/f0cae41a-7935-4fe6-bb87-797a8fc7d820.png" width="932.9556650246305" />
  </figure>
  <p id="eo9i">Этот файл необходимо положить по пути: <strong>repository_path</strong>/data/files,</p>
  <p id="b1hR">где <strong>repository_path </strong>- папка, куда был склонирован репозиторий</p>
  <p id="TdkS"></p>
  <p id="mzDH">Теперь настраиваем скрипт.</p>
  <p id="vTdM">Открываем файл osm2pgsql/osm2pgsql.sh в любом удобном редакторе и меняем следующие переменные</p>
  <figure id="74hn" class="m_custom">
    <img src="https://img3.teletype.in/files/a1/ec/a1ec5fe3-12a6-4fb8-bdb9-6726a499b9be.png" width="584" />
  </figure>
  <p id="glqo"><strong>PG_DATABASE</strong> - название базы данных</p>
  <p id="Jwl2"><strong>PG_USER</strong> - пользователь, которого мы создавали</p>
  <p id="b5T2"><strong>PG_HOST</strong> - ip адрес postgres. У меня указан host.docker.internal, поскольку один контейнер будет подключаться к другому и все это происходит локально. Если у вас БД где-то на сервере, необходимо подставить свой ip</p>
  <p id="gTSX"><strong>PG_PORT</strong> - порт, на котором запущен postgres</p>
  <p id="iiLT">После того, как все нужные операции были проделаны, остается самое интересное - запустить.</p>
  <p id="s9KX">Из папки с репозиторием выполняем следующую команду</p>
  <pre id="CZ50" data-lang="bash">sh osm2pgsql/osm2pgsql.sh</pre>
  <p id="oh2M">Терминал запросит пароль. Необходимо ввести пароль от пользователя, которого создавали. </p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="kupY"><strong>Внимание!</strong> При вводе пароля символы видно не будет. Учтите это.</p>
  </section>
  <p id="SHpk">Если все сделано верно, то вы должны увидеть следующую картину:</p>
  <figure id="KXUT" class="m_custom">
    <img src="https://img1.teletype.in/files/82/c6/82c64a96-bb6a-43b5-b5f9-0971d3a1bc9d.png" width="920" />
    <figcaption>Запуск процесса загрузки данных</figcaption>
  </figure>
  <p id="P2F3">На этом моменте вы можете пойти гулять, играть, пить чай. В общем, все, что душе угодно. </p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="gavz">Данный процесс может занимать от <strong>3х</strong> до <strong>8ми</strong> часов.</p>
  </section>
  <hr />
  <figure id="URAt" class="m_custom">
    <img src="https://img1.teletype.in/files/cc/b7/ccb78cfc-0638-4ea6-b60b-302f000fc34c.png" width="760" />
  </figure>
  <hr />
  <p id="v4rr">Надеюсь вы уже вернулись...</p>
  <p id="rsln">По окончанию работы скрипта у нас должна быть следующая картина</p>
  <figure id="22aI" class="m_custom">
    <img src="https://img2.teletype.in/files/19/5e/195e826b-ab95-4915-970f-8192c9f26f88.png" width="961" />
    <figcaption>Окончание работы скрипта</figcaption>
  </figure>
  <p id="P2N0">На этом моменте работа со скриптом будет закончена и можно вернуться в базу данных.</p>
  <hr />
  <p id="8CXH">Открываем нашу БД и смотрим на таблички. Должно быть 9 таблиц. Если у вас не видно таблиц, то можно нажать на схему <strong>public</strong> ПКМ и выбрать пункт <strong>Refresh</strong>.</p>
  <figure id="UCEz" class="m_custom">
    <img src="https://img3.teletype.in/files/62/71/62712d87-419d-474e-8fc2-396af8e4b3b6.png" width="587.8122448979592" />
  </figure>
  <p id="Lvvp">Давайте заглянем в какую-нибудь табличку, например, <strong>planet_osm_roads.</strong></p>
  <p id="i9cC">Выбираем ее ЛКМ и кликаем на кнопку с иконкой таблицы вверху.</p>
  <figure id="lp3J" class="m_custom">
    <img src="https://img4.teletype.in/files/7a/10/7a10770a-ecec-495c-ac57-c86f4d0a1e4a.png" width="1252" />
  </figure>
  <p id="th33">Перед нами открылось что-то странное и непонятное, похожее на Excel. Без паники! </p>
  <p id="QZc4">Сейчас нас интересует одна единственная колонка.</p>
  <p id="zvkm">Если мы пролистаем вправо до самого конца, то обнаружим колонку <strong>way </strong>и что-то непонятное в данных. Это и есть наша геометрия! Ураааа!</p>
  <p id="CHiK">Мы можем выделить колонку и посмотреть геометрию на карте прям из pgAdmin. Для этого нажимаем на заголовок, чтобы выделить все строки, а затем в заголовке жмем на кнопку с иконкой карты.</p>
  <figure id="vbC3" class="m_custom">
    <img src="https://img4.teletype.in/files/7b/fb/7bfb5605-fa28-436e-bfdf-64f89725f216.png" width="560" />
  </figure>
  <p id="0HzQ">О, чудо!</p>
  <figure id="8WNs" class="m_custom">
    <img src="https://img4.teletype.in/files/7f/de/7fde4ee4-0bbf-47f7-9f74-505647becbd5.png" width="1050" />
  </figure>
  <blockquote id="G0pb">Но, подождите, а почему все белое???</blockquote>
  <p id="ogLM">Давайте посмотрим.</p>
  <p id="GhZz">Сейчас я покажу немного магии postgis.</p>
  <p id="0RRB">Чтобы добавить подложку на эту карту, проекция у геометрии должна быть <strong>EPSG:4326</strong> и никакая другая. Давайте это проверять.</p>
  <p id="hPCp">Выполним запрос</p>
  <pre id="hMZ8" data-lang="sql">SELECT way, ST_SRID(way), ST_ASGeoJSON(way)::jsonb FROM public.planet_osm_roads
LIMIT 10</pre>
  <figure id="LedG" class="m_custom">
    <img src="https://img4.teletype.in/files/77/de/77dee9fb-4bfb-4cec-9f71-edda051bab4f.png" width="980.9999999999999" />
  </figure>
  <p id="h2en">Немного поясню, что сейчас произошло.</p>
  <p id="ugxy">На первых уроках я показывал и рассказывал про GeoJSON. В postgis есть функции для работы с данным форматом. Одну из таких мы сейчас и использовали - <strong>ST_ASGeoJSON</strong>.</p>
  <p id="RiuS">Данная функция позволяет показать геометрию в формате GeoJSON.</p>
  <p id="Zdrw">Тут нам уже наглядно видно две вещи:</p>
  <ol id="D7Aj">
    <li id="fKlV">Если смотреть параметр <strong>crs</strong>, то видно проекцию <strong>EPSG:3857</strong></li>
    <li id="W0uP">Более опытный человек может взглядом на координаты понять, что за проекция (это нарабатывается только насмотренностью)</li>
  </ol>
  <p id="nX5h">Следующая функция - <strong>ST_SRID</strong>.</p>
  <p id="ghea">Если мы не хотим смотреть на координаты, то проекцию можно посмотреть, использовав данную функцию. </p>
  <section style="background-color:hsl(hsl(0, 0%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="1lPn">Итак, мы убедились, что наша проекция не соответствует требованию о наличии EPSG:4326.</p>
  </section>
  <p id="vF6m"> Что будем делать?</p>
  <p id="2si1">Предлагаю не модифицировать данные, а создать на основе них представления (views, вьюхи), в которых как раз перепроецируем геометрию.</p>
  <p id="awcS">View представляет собой таблицу с данными, построенными на основе других данных. То есть мы можем выполнить запрос, собрать данные, а в случае изменения исходной таблицы, View автоматически пересчитается.</p>
  <p id="yYZT">Переходим к созданию вьюхи. Выбираем ПКМ Views =&gt; Create =&gt; View...</p>
  <figure id="f0eb" class="m_custom">
    <img src="https://img1.teletype.in/files/c4/e0/c4e0f7bf-bd96-4e3f-8c3a-5c95746459af.png" width="687" />
  </figure>
  <p id="7qqX">Указываем имя. У меня это <strong>v_planet_osm_roads.</strong></p>
  <p id="yA37">Указываем владельца - созданный нами пользователь.</p>
  <figure id="nlMO" class="m_original">
    <img src="https://img4.teletype.in/files/3a/2a/3a2ae0e6-3a83-4627-a246-e2b64d0a7d6b.png" width="996" />
  </figure>
  <p id="4ekL">Переходим на вкладку <strong>Code</strong>. Здесь нам нужно вставить запрос, которым будет формироваться view.</p>
  <p id="pSoY">Вставляем следующий код</p>
  <pre id="dDZA" data-lang="sql">SELECT 
	ST_Transform(way, 4326) as geometry
FROM public.planet_osm_roads</pre>
  <p id="aDZl">И сохраняем.</p>
  <p id="ZGrP"><strong>ST_Transform </strong>позволяет трансформировать геометрию из одной проекции в другую. В данном случае мы трансформируем геометрию из поля way с проекцией 3857 в 4326.</p>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="FDAU">Важно учитывать, что для <strong>ST_Transform </strong>необходима установленная у изначальной геометрии проекция. Бывают моменты, когда у геометрии нет четко проставленной проекции. В таком случае трансформация будет ругаться. </p>
    <p id="PKAK">Чтобы решить такой вопрос, может потребоваться выполнение двух функций одновременно. Вторая функция <strong>ST_SetSRID(geometry, proj)</strong>. Она позволяет указать, в какой проекции находится геометрия.</p>
    <p id="XvgA">Выполняя <strong>ST_Transform(ST_SetSRID(geometry, proj1), proj2) </strong>получаем нужный результат.</p>
  </section>
  <p id="w5rN"></p>
  <p id="ULI3">Теперь давайте посмотрим, что получилось. View смотреть можно точно так же, как и обычную таблицу.</p>
  <figure id="nsMe" class="m_custom">
    <img src="https://img4.teletype.in/files/70/70/7070a4b4-3949-4c37-a2cf-54f89530133f.png" width="529" />
  </figure>
  <p id="3Vrr">Мы видим таблицу, состоящую из одной колонки.</p>
  <figure id="bAcL" class="m_custom">
    <img src="https://img4.teletype.in/files/f9/0b/f90bd605-c002-4671-965e-15c0e5a1b078.png" width="401" />
  </figure>
  <p id="Cr6g">Попробуем посмотреть геометрию. </p>
  <p id="i9nB">Вуаля! У нас есть подложка!</p>
  <figure id="vi4b" class="m_custom">
    <img src="https://img4.teletype.in/files/f6/87/f6877edb-e69b-401c-8495-4341ff9ee406.png" width="1206" />
  </figure>
  <p id="ryi0"></p>
  <h2 id="SzXz">А теперь немного волшебства</h2>
  <p id="wNaC">Все это круто - таблички, геометрии, какие-то поля, но пока это мало чего нам дает.</p>
  <p id="u36u">Ловите связь.</p>
  <p id="beM2">Вспоминаем формат GeoJSON. </p>
  <p id="bMiU">Мы с вами знаем, что для описания объекта нам необходим тип Feature, properties  и геометрия. Геометрия у нас есть, тип тоже, а где properties?</p>
  <p id="MyS1">Если мы выполним запрос</p>
  <pre id="AqxF" data-lang="sql">SELECT way, name, population, boundary FROM public.planet_osm_roads </pre>
  <p id="FfQs">то увидим табличку из 4 полей, где way - <strong>геометрия</strong>, а остальные - <strong>набор данных.</strong> Так вот, наш набор данных - это и есть properties. То есть мы можем представить представить объект в виде</p>
  <figure>
    <script src="https://gist.github.com/rellowy/f15558ca1e026750f6d8c1915aee039a.js"></script>
  </figure>
  <p id="3uYA">Поле way переехало в geometry, остальные поля уехали в properties, где ключ - наименование поля, значение - значение из строки.</p>
  <p id="k6V9">Таким нехитрым способом мы получили описание объекта.</p>
  <p id="Go2u"></p>
  <p id="pngc">Для описания слоя нам потребуется уже более верхоуровневая сущность - FeatureCollection. Она содержит в себе массив features - объектов. </p>
  <blockquote id="Lr3Z">Ой, так получается, что таблица в БД соответствует слою?</blockquote>
  <p id="BIdg">Да, верно!</p>
  <p id="PZBj"></p>
  <p id="aYi0">Вот мы и создали наши первые слои. А что с этим делать дальше, я покажу в следующих уроках.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rellowy/postgres-in-docker</guid><link>https://teletype.in/@rellowy/postgres-in-docker?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><comments>https://teletype.in/@rellowy/postgres-in-docker?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy#comments</comments><dc:creator>rellowy</dc:creator><title>Создание слоя: поднимаем базу при помощи контейнеров</title><pubDate>Sun, 21 May 2023 18:24:25 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/12/a7/12a750b0-3877-459d-b165-1465fce6e424.png"></media:content><category>База</category><description><![CDATA[<img src="https://img2.teletype.in/files/d0/60/d0607dde-8d3b-4d37-81b7-a73e979f0d64.png"></img>Ремарка]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#0SJE">Котик, какие планы на сегодня?</a></li>
      <li class="m_level_1"><a href="#XApC">Контейнеризация и Docker</a></li>
      <li class="m_level_2"><a href="#rPYE">Контейнеризация</a></li>
      <li class="m_level_2"><a href="#IncG">Docker</a></li>
      <li class="m_level_2"><a href="#ByEF">Особенности контейнеров</a></li>
      <li class="m_level_2"><a href="#83Ga">Ряд терминов из мира Docker</a></li>
      <li class="m_level_2"><a href="#4ZEZ">Docker compose </a></li>
      <li class="m_level_1"><a href="#vLkY">Запуск PostgreSQL в контейнере</a></li>
      <li class="m_level_1"><a href="#o2n3">GUI для работы с БД</a></li>
      <li class="m_level_2"><a href="#MfGg">Подключаемся к БД</a></li>
      <li class="m_level_1"><a href="#pAJ4">Репозиторий с исходным кодом проекта</a></li>
    </ul>
  </nav>
  <hr />
  <h2 id="0SJE">Котик, какие планы на сегодня?</h2>
  <ol id="s6IU">
    <li id="7kuh">Поговорим про контейнеризацию и Docker</li>
    <li id="LKmX">Запустим Postgres в контейнере</li>
  </ol>
  <hr />
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="Smmj"><strong>Ремарка</strong></p>
    <p id="FqZ3">Углубляться в сильные дебри работы контейнеров и Docker в целом не планирую. <u>Я даю лишь поверхностные знания, дабы сложилась полная картинка работы ГИС систем.</u></p>
    <p id="XYV2">Более глубоким изучением тематики вы можете заняться самостоятельно.</p>
    <p id="39jr"></p>
    <p id="ctoz">Решение, описанное в данной статье, не претендует название production ready. </p>
  </section>
  <hr />
  <h2 id="XApC">Контейнеризация и Docker</h2>
  <p id="4m0i">Мы ж вроде только про данные поговорили, причем тут какие-то контейнеры? Еда у котиков вроде в миске обычно... Что вообще происходит???</p>
  <p id="w8ku">Нет, это не те контейнеры, о которых мы могли подумать.</p>
  <h3 id="rPYE">Контейнеризация</h3>
  <p id="n7IM"><strong>Контейнеризация</strong> — это подход к разработке программного обеспечения, при котором приложение или служба, их зависимости и конфигурация упаковываются вместе в образ контейнера.</p>
  <p id="Ff9e">Вспомните грузовые контейнеры. В них помещают какие-либо вещи, которые потом перевозят в другое место.</p>
  <p id="NbWm">Так же и у нас, только у нас в контейнер помещается приложение или сервис, который затем можно запускать на любой ОС, без необходимости устанавливать кучу разного ПО перед этим.</p>
  <p id="qJZB">Такой подход к разработке очень облегчает настройку окружения для разработки, а также позволяет создать одинаковые условия для работы приложения во всех окружениях, будь это тест/прод или среда разработки.</p>
  <h3 id="IncG">Docker</h3>
  <p id="1lTE"><strong>Docker</strong> — это платформа контейнеризации с открытым исходным кодом, с помощью которой можно автоматизировать создание приложений, их доставку и управление. Платформа позволяет быстрее тестировать и выкладывать приложения, запускать на одной машине требуемое количество контейнеров.</p>
  <p id="O3U0">Благодаря контейнеризации и использованию Docker разработчики больше не задумываются о том, в какой среде будет функционировать их приложение и будут ли в этой в среде необходимые для тестирования опции и зависимости. Достаточно упаковать приложение со всеми зависимостями и процессами в контейнер, чтобы запускать в любых системах: Linux, Windows и macOS. Платформа Docker позволила отделить приложения от инфраструктуры. Контейнеры не зависят от базовой инфраструктуры, их можно легко перемещать между облачной и локальной инфраструктурами.</p>
  <h3 id="ByEF">Особенности контейнеров</h3>
  <ul id="3l6b">
    <li id="x0iO">Важнейшая особенность контейнеров — их сравнительно короткий жизненный цикл. Любой контейнер можно остановить, перезапустить или уничтожить, если это необходимо. Данные, которые содержатся в контейнере, при этом тоже пропадут. Так выработалось правило проектирования приложений: не хранить важные данные в контейнере.</li>
    <li id="wMnx">Объем контейнеров измеряется в мегабайтах, поскольку в них упаковывают лишь те процессы и зависимости ОС, которые необходимы для выполнения кода. Легковесные контейнеры быстро запускаются и экономят место на диске.</li>
    <li id="t3zx">Один контейнер соответствует одному запущенному процессу. Отключение отдельного контейнера для отладки или обновления никак не помешает нормальной работе всего приложения.</li>
    <li id="qzeG">Контейнеризация обеспечивает надежную изоляцию процессов и повышает уровень безопасности систем. Приложения, которые работают внутри контейнера, не имеют доступа к основной ОС и не могут на неё влиять.</li>
    <li id="fMLB">Благодаря контейнерам можно автоматизировать развертывание приложений на разных хостах.</li>
    <li id="YniO">Использование контейнеров позволяет перейти с монолита на микросервисную архитектуру. За счет этого ускоряется разработка новой функциональности, поскольку нет опасений, что изменения в одной компоненте затронут всю остальную систему.</li>
    <li id="3Drp">С точки зрения эффективности контейнеры котируются выше виртуальных машин. На одинаковом оборудовании можно запустить большое количество контейнеров, тогда как ВМ будет в разы меньше. Это важно при использовании облачной инфраструктуры — потребуется меньше ресурсов.</li>
  </ul>
  <hr />
  <h3 id="83Ga">Ряд терминов из мира Docker</h3>
  <p id="kjqy"><strong>Образ контейнера</strong>: пакет со всеми зависимостями и сведениями, необходимыми для создания контейнера. Образ включает в себя все зависимости, а также конфигурацию развертывания и выполнения для среды выполнения контейнера. Как правило, образ создается на основе нескольких базовых образов, наслоенных друг на друга в файловой системе контейнера. После создания образ остается неизменным.</p>
  <p id="IZ0I"><strong>Dockerfile</strong>: текстовый файл, содержащий инструкции по сборке образа Docker. Он похож на пакетный сценарий, где первая строка указывает базовый образ, с которого начинается работа, а следующие инструкции устанавливают необходимые программы, копируют файлы и т. п. для создания необходимой рабочей среды.</p>
  <p id="A5ni"><strong>Сборка</strong>: действие по созданию образа контейнера на основе сведений и контекста, предоставленных файлом Dockerfile, а также дополнительных файлов в папке, где создается образ. Сборка образов выполняется с помощью следующей команды Docker:</p>
  <pre id="nS1W" data-lang="bash">docker build</pre>
  <p id="vICO"></p>
  <p id="ROHl"><strong>Контейнер</strong>: экземпляр образа Docker. Контейнер отвечает за выполнение одного приложения, процесса или службы. Он состоит из содержимого образа Docker, среды выполнения и стандартного набора инструкций. При масштабировании службы вы создаете несколько экземпляров контейнера из одного образа.</p>
  <p id="OzDA"><strong>Тома</strong>: файловая систему с возможностью записи, которую может использовать этот контейнер. Поскольку образы доступны только для чтения, а большинству программ требуется возможность записи в файловую систему, тома добавляют слой с поддержкой записи поверх образа контейнера, который программы смогут использовать как файловую систему с возможностью записи.</p>
  <p id="xcLP"><strong>Тег</strong>: метка для образа, которая позволяет различать разные образы или версии одного образа (в зависимости от номера версии или целевой среды).</p>
  <p id="lXaF"><strong>Многоэтапная сборка</strong>: позволяет сократить итоговый размер образов. Например, большой базовый образ, содержащий пакет SDK, можно использовать для компиляции и публикации, а затем можно использовать небольшой базовый образ среды выполнения для размещения приложения.</p>
  <p id="snq1"><strong>Репозиторий (registry):  </strong>место хранения готовых образов Docker. Репозиторий может быть публичный, как Docker Hub, так и приватный - развернутый в рамках корпоративной сети или локально, например, Nexus.<br />Если имя образа похоже на такое - registry.company.name.ru/namespace/name:1.1.0, то скорее всего у вас используется некий приватный репозиторий.<br />Если имя образа содержит только название образа - namespace/name:1.1.0, то, по-умолчанию, образы загружаются с Docker Hub.<br /><br />При загрузке образов docker смотрит наличие скаченных или собранных локально. Если имя и тег совпадут, тогда скачивать ничего не будет.</p>
  <hr />
  <h3 id="4ZEZ">Docker compose </h3>
  <p id="cyRt"><strong>Docker compose</strong> — это инструментальное средство, входящее в состав Docker. Оно предназначено для решения задач, связанных с развёртыванием проектов.</p>
  <p id="EXVF">Зачем он нужен, если Docker сам по себе самодостаточный?</p>
  <p id="M5O2">Программисты, а может и DevOPS&#x27;ы, по своей натуре, довольно ленивые создания. Кому, как ни котикам, это знать!😂<br />Docker compose призван облегчить жизнь разработчикам. </p>
  <p id="oI03">Представим ситуацию... Да чего представлять, она такой и будет в рамках разработки нашего ГИС. <br />Нам необходимо запустить несколько приложений:</p>
  <ul id="tH1N">
    <li id="daxG">PostgreSQL</li>
    <li id="QHGH">Geoserver</li>
    <li id="ikNP">Frontend</li>
    <li id="WjTw">Backend</li>
  </ul>
  <p id="pOjm">В случае использования Docker в чистом виде, на каждое приложением нам бы пришлось написать свою команду для запуска. Такие команды обычно очень длинные, например:</p>
  <figure>
    <script src="https://gist.github.com/rellowy/20001f280feb6cd31bc6aab433e91c18.js"></script>
    <figcaption>Пример команды запуска контейнера</figcaption>
  </figure>
  <p id="dMy1">А если нам потребуется перед запуском контейнера оставить его, то добавится к этому еще как минимум 2 команды:</p>
  <pre id="px0V" data-lang="bash">docker container stop container_name &amp;&amp; docker container rm container_name</pre>
  <p id="bzvs">Согласитесь, выглядит страшновато и не супер удобно. Необходимо запоминать описание флагов (или часто подглядывать в docker help).</p>
  <p id="W163">Docker compose призван решить эту проблему. Он предоставляет возможность описания всех необходимых параметров запуска контейнера в yaml файле. Также он продвигает идеологию запуска контейнеров в виде отдельных сервисов. </p>
  <p id="LGYC">Что это нам должно сказать?</p>
  <p id="I16b">В одном yaml файле можно прописать N разных сервисов и запустить/остановить их все одной командой. Помимо запуска сервисов, сразу можно настроить общие тома и создать, а затем объединить, контейнеры в единую сеть.</p>
  <hr />
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="by3q">Сейчас очень важно понять - все, что запущено внутри контейнеров, запущено в рамках своей сети. Если попытаться в приложении использовать в качестве хоста для подключения ключевое слово localhost или ip 127.0.0.1, это приведет к тому, что приложение попытается обратиться к сети, в рамках которой работает контейнер, наружу оно не пойдет.</p>
    <p id="eMn3"></p>
    <p id="hIge">Исключением в этом случае будет ручное указание работы сети docker в режиме моста (bridge).</p>
  </section>
  <hr />
  <h2 id="vLkY">Запуск PostgreSQL в контейнере</h2>
  <p id="gbFj">Сегодня мы с вами рассмотрим самый простой вариант запуска контейнера с помощью Docker и Docker Compose.</p>
  <p id="Sa6A">YAML файл для запуска контейнера выглядит следующим образом</p>
  <figure id="rLZw" class="m_original">
    <img src="https://img2.teletype.in/files/d0/60/d0607dde-8d3b-4d37-81b7-a73e979f0d64.png" width="391" />
    <figcaption>Пример YAML</figcaption>
  </figure>
  <p id="6k52"></p>
  <p id="q0sE">В самом верху файла всегда указывается version. Версия эта относится конкретно к yaml. За счет нее docker compose понимает, какой набор параметров он может обработать. <br />Версии обновляются, посмотреть различия можно <a href="https://docs.docker.com/compose/compose-file/compose-versioning/" target="_blank">тут</a>.</p>
  <p id="ITgd"><br />Переходим к services. Данная секция представляет собой именованный массив сервисов/контейнеров. <u>postgres</u> - название сервиса.</p>
  <p id="zQ5E">Под названием сервиса указывается уже ряд параметров, которые при использовании Docker мы бы прописывали в команде в виде отдельных ключей. Кратко пробегусь по каждому из них.</p>
  <p id="eUOd"></p>
  <ul id="Fx36">
    <li id="nAKG"><strong>platform</strong> - указывает контейнеру, какую платформу использовать в качестве основы. Платформу обычно никто не указывает, но мне она нужна, потому что на Apple M1 контейнер без этого просто не стартует</li>
    <li id="qbqa"><strong>container_name</strong> - имя контейнера</li>
    <li id="S9Ju"><strong>image</strong> - базовый образ контейнера. Будет скачиваться с Docker Hub</li>
    <li id="bFGi"><strong>restart</strong> - политика перезапуска контейнера. Наш контейнер будет пытаться запуститься заново, во всех случаях, кроме того, когда мы его останавливает вручную</li>
    <li id="TCBG"><strong>ports </strong>- поскольку posgres у нас запущен как сервис внутри контейнера на определенном порту, нам необходимо иметь возможно достучаться до этого порта. Для этого используется маппинг портов - внешний_порт:внутренний_порт</li>
    <li id="PD40"><strong>volumes</strong> - настройка файловой системы, томов. Поскольку это база данных, нам важно сохранять информацию на основной ОС, чтоб в случае перезапуска контейнера сохранить всю информацию. Указание мапппинга аналогично портам - внешная_папка:внутренняя_папка. <br />Конструкция <strong>${PWD}  </strong>означает указание пути до текущей директории, откуда выполняем команду. Например, мы находимся в директории /users/cat/project/gis, выполняем команду в терминале из этой директории. Полный путь до папки в этом случае будет выглядеть как <strong>/users/cat/project/gis/data/db.</strong></li>
  </ul>
  <figure id="6UjP" class="m_original">
    <img src="https://img3.teletype.in/files/2f/22/2f22145a-90a2-4745-8516-4ab44fac47e9.png" width="399" />
  </figure>
  <ul id="YQIN">
    <li id="IeFX"><strong>environment</strong> - переменные окружения внутри контейнера. <br />У меня присутствует интересная переменная $PG_PASS. Она нужна для того, чтобы не светить пароль в git. Вы при локальной разработке можете забить строку с паролем прямо в файл и не думать об этом.<br />Описание переменных окружения, необходимых для нормальной работы Postgres в рамках Docker вы можете найти на странице образа в Docker hub.</li>
  </ul>
  <p id="27vo"></p>
  <p id="0CeE">Обратите внимание, никакой сети я не указывал. Docker создаст ее автоматически.</p>
  <p id="e5oF"></p>
  <p id="R9eO">Теперь нам осталось выполнить только команду</p>
  <pre id="cnLO" data-lang="bash">PG_PASS=YOUR_PASSWORD docker-compose -f postgres/docker-compose.yml up -d</pre>
  <p id="510T"></p>
  <p id="Sk9O">Выполнив команду</p>
  <pre id="tJZD" data-lang="bash">docker ps -a</pre>
  <p id="2SnN">убеждаемся в наличии запущенного контейнера, работающего на определенном порту</p>
  <figure id="VspI" class="m_original">
    <img src="https://img4.teletype.in/files/fc/e7/fce7ebc6-6450-4d7a-84b2-2b396d7a5264.png" width="871" />
    <figcaption>Запущенные контейнеры</figcaption>
  </figure>
  <p id="8DyN">Если у вашего контейнера STATUS похож на &quot;Exited...&quot;, то скорее всего вы что-то сконфигурировали неправильно, или образ содержит ошибку. </p>
  <p id="5Toz">Узнать, что произошло, можно, выполнив следующую команду</p>
  <pre id="pe2J" data-lang="bash">docker logs container_name</pre>
  <p id="JVNf"></p>
  <p id="ZNUI">Как мы видим, у нас все прошло успешно. Можно двигаться дальше.</p>
  <hr />
  <h2 id="o2n3">GUI для работы с БД</h2>
  <p id="Su3u">Не все котики захотят работать в командной строке. Вводить команды, запоминать их... Не наш подход.<br />Кстати о командах. В контейнере можно выполнять команды.</p>
  <pre id="1EcU" data-lang="bash">docker exec -it container_name your_command</pre>
  <p id="KMPZ"><br />Иногда хочется зайти прямо внутрь контейнера и пошалить там. Для этого можно вызвать bash или sh, но всегда это доступно. С этим надо быть максимально аккуратным. Если ваш контейнер внутри работает из под пользователя root, то стоит задуматься, а не сменить ли образ или пересобрать под другим пользователем. С таким пользователем можно огрести множество проблем с безопасностью, например, подключив том к контейнеру, можно перейти в него и выполнить пару команд на удаление каких-нибудь папок.</p>
  <p id="hZfT">Ладно, это было лирическое отступление. Возвращаемся к GUI.</p>
  <p id="jxBu">На сегодняшний момент есть два варианта, как можно удобно работать с базой - в IDE или воспользоваться pgAdmin.</p>
  <p id="ZzKW">Я предпочитаю именно второй вариант. Там, кстати, можно посмотреть объекты прямо на карте.</p>
  <hr />
  <h3 id="MfGg">Подключаемся к БД</h3>
  <p id="0lWp">У вас после установки первый раз будет только одна группа серверов. Кликаем по ней ПКМ и регистрируем новый сервер.</p>
  <figure id="Kc26" class="m_original">
    <img src="https://img2.teletype.in/files/dd/76/dd765541-e270-42fd-bf92-5b128405dc4d.png" width="739" />
    <figcaption>Первичная регистрация сервера</figcaption>
  </figure>
  <p id="mvZu">На вкладке General нам необходимо указать название нашего сервера. У меня это будет <strong>Development. </strong>Остальные настройки не меняем и переходим на вкладку Connection.</p>
  <figure id="6zAe" class="m_original">
    <img src="https://img2.teletype.in/files/57/57/57579f13-5334-45b0-85a3-3fcf3f1e87e2.png" width="500" />
    <figcaption>Вкладка General</figcaption>
  </figure>
  <p id="cHm0">На вкладке Connection нам необходимо заполнить следующие поля:</p>
  <ul id="UmWO">
    <li id="5DWo">Host name/address - ip адрес нашего сервера</li>
    <li id="0x0O">Port - порт</li>
    <li id="2vEP">Maintenance database - база данных, которая будет открываться по-умолчанию после коннекта к серверу</li>
    <li id="FPzX">Username - пользователь из под которого коннектимся к серверу</li>
    <li id="Czzu">Password - пароль для пользователя</li>
    <li id="sqUm">Save password? - включаем, если хотим не вводить постоянно пароль.</li>
  </ul>
  <p id="4bYg">Итак,</p>
  <ul id="TNyV">
    <li id="cQjm">Host name - 127.0.0.1 или localhost. Поскольку мы подключаемся с ОС к контейнеру, у которого наружу проброшен порт, мы делаем это в рамках своей сети, соответственно, можем использовать localhost</li>
    <li id="sf2z">Port - внешний порт, у нас он равен внутреннему, а именно, 5432</li>
    <li id="39Gi">Maintenance database - не меняю, так как баз у нас пока еще нет других</li>
    <li id="HOpA">Username - пока пользователей не заводили, поэтому оставляю суперпользователя postgres</li>
    <li id="OwcD">Password - помните я говорил про переменную $PG_PASS? Так вот она и содержит пароль для суперпользователя. Указываем его в поле</li>
    <li id="8NVL">Save password? - естественно включаю</li>
  </ul>
  <figure id="Ii54" class="m_original">
    <img src="https://img4.teletype.in/files/78/0e/780ef837-67f8-47fe-9035-9d028be954ef.png" width="621" />
    <figcaption>Ввод всех полей на вкладке Connection</figcaption>
  </figure>
  <p id="Mht7"></p>
  <p id="iP6N">Остальные вкладки мы не трогаем. Нажимаем <strong>save</strong> и проверяем, что сервер успешно добавлен, присутствует бд Postgres.</p>
  <figure id="SuPf" class="m_original">
    <img src="https://img1.teletype.in/files/89/ab/89ab2bc6-5a78-4f5f-b674-4ac15f9dc473.png" width="326" />
    <figcaption>Созданный сервер</figcaption>
  </figure>
  <p id="OeQk">Так же можем убедиться в наличии расширения PostGIS.</p>
  <figure id="7PRO" class="m_original">
    <img src="https://img3.teletype.in/files/66/de/66ded83b-e374-4fdf-804d-de5ec24cd8c1.png" width="363" />
    <figcaption>Смотрим наличие расширения PostGIS.</figcaption>
  </figure>
  <hr />
  <p id="HzE4">Чтобы останавливать контейнер, используем команду</p>
  <pre id="zVMQ" data-lang="bash">docker-compose -f postgres/docker-compose.yml down -v</pre>
  <hr />
  <h2 id="pAJ4">Репозиторий с исходным кодом проекта</h2>
  <p id="yuAl">Я создал репозиторий с исходным кодом проекта. Разрабатывать будем там, всем примеры кода можно будет посмотреть там. <br />Долго не радуйтесь, поскольку проект будет довольно большой, в один прекрасный момент я создам для себя приватный репозиторий, в рамках которого продолжу разработку. Я не хочу, чтобы мой проект нагло своровали и использовали для своих нужд, а также я очень надеюсь, что вы будете кодить параллельно со мной и вкладывать частичку себя в вашу систему.</p>
  <p id="Oy4T">Надеюсь, мы меня поймете и поддержите 🐱</p>
  <p id="ga7j"></p>
  <hr />
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="Exux" data-align="center"><a href="https://github.com/rellowy/gis" target="_blank">Репозиторий</a></p>
  </section>
  <hr />

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rellowy/geo-in-postgres</guid><link>https://teletype.in/@rellowy/geo-in-postgres?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><comments>https://teletype.in/@rellowy/geo-in-postgres?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy#comments</comments><dc:creator>rellowy</dc:creator><title>Создание слоя: хранение гео данных</title><pubDate>Sun, 21 May 2023 15:51:54 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/6f/fd/6ffd6270-a775-4723-8c14-1a9ae963789a.png"></media:content><category>База</category><description><![CDATA[<img src="https://img3.teletype.in/files/a7/4e/a74ed39d-cd51-41b1-8bfe-5c85a3085697.png"></img>В предыдущих статьях я обмолвился, что мы будем хранить данные в БД Postgres.  Почему именно он? На самом деле, все просто до безумия - самая распространенная БД, очень сильно себя зарекомендовавшая. Postgres используют многие, поэтому не вижу никаких причин его не использовать.]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="hnDK">В предыдущих статьях я обмолвился, что мы будем хранить данные в БД Postgres.  Почему именно он? На самом деле, все просто до безумия - самая распространенная БД, очень сильно себя зарекомендовавшая. Postgres используют многие, поэтому не вижу никаких причин его не использовать.</p>
  </section>
  <hr />
  <nav>
    <ul>
      <li class="m_level_1"><a href="#1fBT">Чем же мы сегодня будем заниматься?</a></li>
      <li class="m_level_1"><a href="#inVp">Немного теории БД</a></li>
      <li class="m_level_2"><a href="#0HW0">Основные понятия, которыми будем оперировать</a></li>
      <li class="m_level_2"><a href="#3BYW">Как хранить гео данные в Postgres?</a></li>
    </ul>
  </nav>
  <hr />
  <h2 id="1fBT">Чем же мы сегодня будем заниматься?</h2>
  <ol id="EyHH">
    <li id="b7pK">Вспомним немного теории баз данных</li>
    <li id="W5WT">Посмотрим, что нам будет помогать в хранении и обработке гео данных</li>
  </ol>
  <hr />
  <h2 id="inVp">Немного теории БД</h2>
  <p id="UzTP"><strong>PostgreSQL</strong> - это мощная реляционная база данных с открытым исходным кодом бизнес-уровня. Она позволяет использовать реляционные SQL и нереляционные JSON данные и запросы.</p>
  <p id="I7kZ">Я думаю, все прекрасно знают, что реляционная модель предусматривает единственный способ представления данных – в виде набора двумерных таблиц.</p>
  <h3 id="0HW0">Основные понятия, которыми будем оперировать</h3>
  <hr />
  <section style="background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="EpXy">Ремарка</p>
    <p id="3AZO">Если вы не читали <a href="https://teletype.in/@rellowy/fsVfkdBwoAu" target="_blank">статью про форматы данных</a>, рекомендую сначала вернуться к ней</p>
  </section>
  <hr />
  <p id="8bgR">Из чего состоит таблица? Вы скажите, что все просто - колонки и строки. И да, вы окажитесь правы, но я есть другие понятия - поля (они же атрибуты) и кортежи.</p>
  <hr />
  <p id="5hsd"><strong>Поля или атрибуты - </strong>описание колонок таблицы. Они состоят из описания</p>
  <ul id="1tOn">
    <li id="kE1H">Типа данных</li>
    <li id="JxVH">Признака обязательности - может ли быть пустым поле</li>
    <li id="lK3T">Длинна значения, если тип данных позволяет ограничить</li>
    <li id="xJcm">Признак главного ключа (primary key)</li>
    <li id="qCQj">Признак внешнего ключа (foreign key)</li>
  </ul>
  <p id="iPuM">Есть еще ряд параметров, но нам хватит и этого 🙃</p>
  <p id="SS1Q">Ключи какие-то нам тут даешь... Какие двери ими открывать? </p>
  <p id="vEzR"><strong>Главный ключ (он же primary key</strong>) обычно вешается на поле с идентификатором объекта. С его помощью можно однозначно идентифицировать, какой перед нами объект.</p>
  <p id="ub1E">Primary key может быть несколько. Такое явление называется составным ключом. На практике именно в ГИС я такого не наблюдал, но, если понадобится, разберемся детально в процессе.</p>
  <p id="IsD8"></p>
  <p id="36xr"><strong>Внешний ключ (foreign key)</strong> обычно служит для связи двух таблиц между собой. Обычно в него записывают значение primary key другой таблицы. Таких ключей может быть несколько в рамках одной таблицы. </p>
  <p id="gDWj">Установка признака внешнего ключа влияет на консистентность данных. Иными словами, если не проставить этот признак, то в поле можно будет записать индетификатор, которого не существует в связной таблице.</p>
  <p id="9QbI"><strong>Например. </strong>Предположим, мы решили организовать склад хранения колес. Для этого нам необходимо иметь данные об автомобиле и его владельце, а также при приеме колес на хранение нужно учитывать ряд параметров - радиус колеса и тд. В этом случае можно схему БД можно представить следующим образом:</p>
  <figure id="IKNU" class="m_original">
    <img src="https://img3.teletype.in/files/a7/4e/a74ed39d-cd51-41b1-8bfe-5c85a3085697.png" width="885" />
    <figcaption>Пример БД</figcaption>
  </figure>
  <p id="sIWx">Получается, владелец (owners) может иметь несколько автомобилей. У автомобилей (cars), как мы знаем, по 4 колеса (wheels). Везде получается связь 1 ко многим.</p>
  <hr />
  <p id="7pPR">Что же такое кортеж? </p>
  <p id="mOPZ">Кортежем является строка таблицы, содержащая данные по полям.</p>
  <hr />
  <p id="k4de">Ну и зачем же ты нам это рассказываешь?<br /><strong>Следите за ходом мысли!</strong></p>
  <p id="nsSk">Немного вернемся к самой первой статье и вспомним, что такое объект с точки зрения картографии.</p>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="1u8A"><strong>Объект</strong> - сущность, содержащая в себе геометрию и ее атрибутивный состав. <u>Объект без геометрии существовать не может.</u></p>
  </section>
  <p id="HUe6">Из этого определения мы можем сделать вывод, что:</p>
  <ol id="mfxM">
    <li id="hkOn">Для того, чтобы у нас был именно картографический объект, необходимо иметь поле типа Geometry</li>
    <li id="ev3v">Атрибутивный состав объекта - набор полей таблицы</li>
  </ol>
  <p id="RxOP">Что же получается?</p>
  <p id="pCdX">А получается интересная штука. </p>
  <p id="juts">Слой получается путем создания таблицы, одним из полей которой является геометрия. <u>С точки зрения GeoJSON, таблицу можно представлять в виде FeatureCollection, каждый кортеж которой - Feature, а поля таблицы попадают в properties.</u></p>
  <p id="AQ6a">Иными словами, в 90% случаев одна таблица в БД соответствует одному слою. </p>
  <p id="jsTw"><strong>Бывают исключения. </strong>Например, мы хотим, чтобы на один объект приходилось несколько геометрий, каждая из которых могла быть стилизована по-своему.<br />В таком случае разумно будет создать две таблицы и связать их между собой в отношении 1 ко многим, либо использовать GeometryCollection и JSON поле с массивом атрибутов для геометрий. <br />Если мы будем делать несколько таблиц, то нам придется их все равно соединить в одну таблицу (создать представление (view) данных), где будет дублирование информации. Можно обойтись без представления, поскольку Geoserver&#x27;у можно скормить SQL, в котором прописать связь. На мой взгляд, это не самый удачный вариант, потому что можно забыть об этом SQL, изменить таблицу в бд, а потом сидеть и гадать, почему же у меня слой перестал выводится или что-то не отображается.</p>
  <hr />
  <h3 id="3BYW">Как хранить гео данные в Postgres?</h3>
  <p id="RFJl">Вы можете задаться вопросом, а как же хранить гео данные, если Postgres по-умолчанию не умеет?</p>
  <p id="Eytu">Вы всегда можете воспользоваться вариантом JSON полей, куда прописывать GeoJSON, но это не наш случай. В нашем варианте мы будем рассматривать расширение PostGIS.</p>
  <p id="JqDB"><strong>PostGIS</strong> — программное расширение с открытым исходным кодом, расширяющее пространственную базу данных системы управления PostgreSQL. Расширение добавляет поддержку географических объектов, благодаря чему появляется возможность выполнять запросы местоположения в SQL.PostGIS позволяет хранить ряд географических и пространственных данных — точек, ломаных линий, полигонов, растр, а также использовать их для разных операций, например, поиска.</p>
  <p id="mbTz">PostGIS в PostgreSQL используется для снятия ограничений, расширения функций и позволяет применять:</p>
  <ul id="cn3q">
    <li id="21K4">растровые данные;</li>
    <li id="USSo">функции создания геометрий и управления ими (создание и удаление полей с географическими данными, запросы скриптов, библиотек);</li>
    <li id="5BB1">функции редактирования геометрий и их форматированного вывода;</li>
    <li id="xHbT">расширенные 2D- и 3D-функции, в том числе для определения пересечений в 3D-пространстве);</li>
    <li id="K1hr">инструменты для определения пространственных отношений и измерений (например, для сравнения расстояния по плоскости и на сфере);</li>
    <li id="7tP0">функции создания и отображения растров в удобном формате (например, в JPEG или PNG);</li>
    <li id="k6kd">инструменты обработки растров (очищение рельефа, векторизация, увеличение или уменьшение яркости).</li>
  </ul>
  <p id="i4SR">Возможности связки PostGIS и PostgreSQL на практике могут использоваться для определения:</p>
  <ul id="ixvw">
    <li id="2cu4">расстояния от точки до точки;</li>
    <li id="iDwA">ближайшей точки между извилистыми улицами на местности;</li>
    <li id="e9E2">улицы или даже дома по определенным координатам;</li>
    <li id="E6Eg">количества домов, попадающих в заданную область пространства;</li>
    <li id="C2Rz">количества объектов, находящихся поблизости с заданной точкой;</li>
    <li id="nOl9">площади, расстояний, длин, периметров заданных объектов и множества других данных.</li>
  </ul>
  <p id="eZqw">Например, PostgreSQL с предустановленным расширением PostGIS может использоваться для:</p>
  <ul id="hROd">
    <li id="Vd7l">вычисления площади города, региона, государства;</li>
    <li id="jGKj">поиска ближайшей кофейни или магазина;</li>
    <li id="voEQ">построения карты (в том числе растровой) с отображением заданных объектов;</li>
    <li id="K0Do">поиска объектов или местностей, отвечающих заданным критериям (самый крупный город, самая южная страна, самая высокая точка).</li>
  </ul>
  <p id="5DFi">Именно благодаря нему у нас и появляется возможность создавать поля с типом Geometry.</p>
  <p id="evNB">Все возможности PostGIS описывать не буду, иначе это будет долго и очень много. Будем разбирать на практике, быстрее поймете 🙃</p>
  <hr />
  <p id="d1sD">Поскольку нам предстоит изучение довольно большого объема информации, я решил поделить эту статью на несколько частей.</p>
  <p id="apNu">В следующей части мы коротко пробежимся о том, что такое контейнеризация и docker, а также запустим Postgres с установленным PostGIS.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rellowy/geoserver-wms-wfs</guid><link>https://teletype.in/@rellowy/geoserver-wms-wfs?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><comments>https://teletype.in/@rellowy/geoserver-wms-wfs?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy#comments</comments><dc:creator>rellowy</dc:creator><title>Geoserver - WMS и WFS</title><pubDate>Tue, 09 May 2023 20:33:51 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/a0/85/a085c8a4-52e7-459e-a05c-ced96171856d.png"></media:content><category>Geoserver</category><description><![CDATA[Все мы знаем, что обнять большого слона за один раз нам не под силу, ведь мы с вами маленькие.]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="sfis">Все мы знаем, что обнять большого слона за один раз нам не под силу, ведь мы с вами маленькие.</p>
  </section>
  <p id="jwcR">Geoserver представляет собой веб-сервер, обеспечивающий стандартным клиентам, таким, как веб-браузеры и настольные ГИС, доступ к хранящимся в различных форматах картам и данным. Это означает, что вы можете хранить ваши пространственные данные почти в любом предпочитаемом вами формате.</p>
  <p id="3Wg0">Geoserver — это эталонная реализация стандартов Open Geospatial Consortium (OGC) <em>WFS (Web Feature Service)</em> и <em>WCS (Web Coverage Service)</em>, а также высокопроизводительная сертифицированная реализация <em>WMS (Web Map Service)</em>. Geoserver является основным компонентом Geospatial Web.</p>
  <p id="Qxvb">Поскольку geoserver реализует несколько различных картографических, изучать мы будем весь функционал постепенно, по мере нашего продвижения по миру картографии.</p>
  <hr />
  <h2 id="EwlU">Введение</h2>
  <p id="bUuv">Предположим, у нас имеется большой объём данных, например, данные по всем зданиям города Санкт-Петербург, хранящиеся в базе данных PostgreSQL <u>(об этом мы еще поговорим в одной из следующих статей),</u> и какой-нибудь разработчик принимает решение использовать их в своем приложении. Прежде всего он вынужден будет реализовать все необходимые операции (извлечение, фильтрацию и т.п.) c помощью SQL. Если мы вдруг решим сменить способ хранения (например, перейдем на файловый вариант) или появится более качественный источник аналогичных данных, но в другом формате и разработчику нужно будет переключиться на него, то он будет вынужден полностью переписывать ту часть своего приложения, которая отвечает за извлечение данных из хранилища.</p>
  <p id="kUyG">Основной задачей данных сервисов является предоставление универсального интерфейса доступа к данным, убирая необходимость прямого доступа к хранилищу. </p>
  <p id="NQfh">Важно отличать Web Feature Service (WFS) от Web Map Service (WMS). </p>
  <p id="cHvm"><strong>WMS</strong> предназначен для передачи уже отрендеренных данных, тех самых тайлов.</p>
  <p id="tfeX"><strong>WFS</strong> отдаёт данные в оригинальном виде: в стандарте указан GML, однако никто не запрещает отдавать и в виде других форматов, например, изученном нами ранее GeoJSON. </p>
  <p id="3TVQ">Можно провести аналогию: скомпилированная программа (WMS) и исходный код (WFS).</p>
  <hr />
  <h2 id="Xkvv">WMS - Web Map Service</h2>
  <p id="ior7">Как мы уже выяснили, WMS позволяет нам получать отрендеренные тайлы. Если говорить простыми словами - картинки с изображением объектов слоя, однако есть методы, возвращающие информацию о слое. </p>
  <p id="K7qk">Рассмотрим доступные нам методы.</p>
  <ul id="KHan">
    <li id="NnHC">GetCapabilities - возвращает параметры WMS (такие как формат изображения карты и совместимость версий WMS) и доступные слои (ограничивающая рамка карты (bounding box), системы координат, URI данных и является ли слой в основном непрозрачным или нет).</li>
    <li id="iYyd">GetMap - возвращает изображение карты. Параметры включают: ширину и высоту карты, систему координат, стиль рендеринга, формат изображения.</li>
    <li id="wxtW">GetFeatureInfo - позволяет при клике на тайл получить информацию об объектах в данной точке.</li>
    <li id="tttZ">GetLegendGraphic - возвращает изображение легенды карты, предоставляя визуальное руководство по элементам карты.</li>
  </ul>
  <p id="utXt"></p>
  <h3 id="fsAe">Метод GetMap - основные параметры</h3>
  <figure>
    <script src="https://gist.github.com/rellowy/1efeba1dbc7829a81e3930517fbc85c3.js"></script>
    <figcaption>Таблица параметров запроса GetMap</figcaption>
  </figure>
  <p id="2Amf">На данном этапе нам важно учитывать особенности Geoserver, а именно:</p>
  <ol id="eRXb">
    <li id="xg5P">Количество стилей в параметре STYLES должно соответствовать количеству слоев в параметре LAYERS</li>
    <li id="ie47">Количество фильтров в параметре CQL_FILTER  должно соответствовать количеству слоев в параметре LAYERS</li>
    <li id="0tvm"> Если одному из слоев нам не нужно применять фильтрацию, то к нему необходимо применить специальное слово INCLUDE</li>
  </ol>
  <p id="mbuK">За счет регулирования параметров ширины, высоты, а также bbox, можно выводить тайлы на карту двумя способами:</p>
  <ol id="5bPE">
    <ol id="eVH8">
      <li id="1vN0">Маленькими кусочками</li>
      <li id="0cZr">Один тайл, захватывающий всю область видимости карты сразу</li>
    </ol>
  </ol>
  <p id="Divx">Первый способ позволяет отдавать пользователю информацию на просмотр гораздо раньше, однако в этом случае видно, как прогружается карта.</p>
  <p id="DPCL">Второй способ заставляет пользователя немного подождать, однако на выходе мы получаем сразу полную картинку.</p>
  <p id="5E6U"></p>
  <h3 id="CubG">Метод GetFeatureInfo - основные параметры</h3>
  <figure>
    <script src="https://gist.github.com/rellowy/5848f3e4fb93e6da074c2241b7e80ed9.js"></script>
    <figcaption>Таблица параметров метода GetFeatureInfo</figcaption>
  </figure>
  <p id="9ULt">Также ваша карта может отдавать в GetFeatureInfo параметры, как и у GetMap. Это абсолютно нормально, пугаться этого не стоит. </p>
  <p id="LoTs">Если есть какие-то лишние параметры, которые не описаны в стандарте, то учитываться они не будут. </p>
  <p id="Lnnl">Если название параметра написано с ошибкой, а он обязательный, Geoserver вам об этом скажет, ровно как и сообщит о любой другой ошибке или отклонении от стандарта.</p>
  <p id="ct3m"></p>
  <h3 id="g04S">Метод GetCapabilities - основные параметры</h3>
  <figure>
    <script src="https://gist.github.com/rellowy/5b6862c1968b672d7fd4b364771d0d98.js"></script>
    <figcaption>Таблица параметров метода GetCapabilities</figcaption>
  </figure>
  <hr />
  <h2 id="ogKN">WFS - Web Feature Service</h2>
  <p id="G1n3">Основная задача WFS-сервисов - это предоставление разработчикам (или конечным потребителям данных) универсального интерфейса доступа к пространственным данным, убирающего необходимость прямого доступа к хранилищу и таким образом делающего его прозрачным для пользователя. В этом случае задача по реализации доступа к различным хранилищам данных ложится на плечи WFS-сервера, то есть WFS сервер выступает в качестве прослойки между хранилищем данных и пользователем данных (к пользователям данных могут относится и в том числе и программы).</p>
  <p id="Ucdd"></p>
  <p id="rTJW">Стандарт WFS описывает 6 методов, каждый из которых отвечает за выполнение той или иной операции:</p>
  <ul id="n8XT">
    <li id="zP8Z">GetCapabilities</li>
    <li id="4v29">DescribeFeatureType</li>
    <li id="b8s5">GetFeature</li>
    <li id="9Mq3">GetGMLObject</li>
    <li id="esqr">Transaction</li>
    <li id="pzqX">LockFeature</li>
  </ul>
  <p id="n12A">Поскольку мы рассматриваем базовые возможности WFS, то остановимся на рассмотрении только первых трёх методов: GetCapabilities, DescribeFeatureType и GetFeature. GetGMLObject - довольно сложная штука и вряд ли вы с ней столкнётесь, а последние два метода Transaction и LockFeature предназначены для выполнения операций по редактированию объектов.</p>
  <p id="WhOy"></p>
  <p id="7E8Z">У всех запросов будет примерно одинаковый набор параметров. Дабы их каждый раз не повторять, вынесу отдельно</p>
  <figure>
    <script src="https://gist.github.com/rellowy/85461ad28c04547e5c9a6518f2c17c41.js"></script>
    <figcaption>Параметры WFS</figcaption>
  </figure>
  <p id="mEyw"></p>
  <h3 id="o5Ea">Метод GetCapabilities</h3>
  <p id="4a5k">Если вы внимательно посмотрите на название, то заметите, что такой метод уже был в WMS. Смысл этого метода точно такой же, что и в WMS.</p>
  <p id="P8E0"></p>
  <h3 id="bF92">Метод DescribeFeatureType</h3>
  <p id="aW7x">В ходе работы может потребоваться узнать дополнительную информацию об отдельных слоях, опубликованных по WFS. Для этого предназначен метод DescribeFeatureType. Данный метод возвращает список доступных слоёв или описание атрибутов, если в запросе передано имя конкретного слоя.</p>
  <p id="KPzG"></p>
  <h3 id="WOl9">Метод GetFeature</h3>
  <p id="dOZY">Описанные выше два метода конечно полезны, однако наиболее важный метод ради которого и был разработан стандарт WFS - метод GetFeature, позволяющий запрашивать с сервера непосредственно сами данные. Данный метод необходимо использовать совместно с параметром <strong>typeName</strong>, определяющем имя слоя, объекты которого мы запрашиваем.</p>
  <p id="u1xB"></p>
  <p id="xBYJ">Если необходимо запросить информацию об одном объекте, то зная его id, то можно использовать параметр <strong>featureID.<br /></strong>Например,</p>
  <pre id="5ATB">?service=WFS&amp;version=1.1.0&amp;request=GetFeature&amp;typename=space:buildings&amp;featureID=buildings.7</pre>
  <p id="B9H6">featureID должен выглядеть как <strong>название_слоя.id</strong></p>
  <p id="a0ga"></p>
  <p id="jlGx">C помощью параметра <strong>maxFeatures</strong> можно ограничить количество получаемых данных. Здесь же можно передать параметр <strong>startIndex, </strong>который поможет получать информацию дозировано, а может быть и сделать пагинацию без написания своего бэкенда.</p>
  <pre id="ZUx2">?service=wfs&amp;version=1.1.0&amp;request=GetFeature&amp;typeName=space:buildings&amp;maxFeatures=10&amp;startIndex=11</pre>
  <p id="GDjV">Такой запрос означает, что мы получим 10 объектов, начиная с 11-го.</p>
  <p id="mX5s">При этом Geoserver нам отдаст дополнительную информацию о кол-ве всего объектов в слоев, а также повторит информацию о кол-ве полученных объектов, равного параметру maxFeatures.</p>
  <p id="ww4k"></p>
  <p id="osVs">Ограничить список возвращаемых атрибутов можно с помощью параметра <strong>propertyName</strong>, передавая значения имен атрибутов через запятую, а отсортировать полученный результат с помощью параметра <strong>sortBy</strong></p>
  <ul id="FQ7U">
    <li id="nOWu">sortBy=value+D - по убыванию</li>
    <li id="5RUT">sortBy=value+A - по возрастанию</li>
  </ul>
  <pre id="51vY">?service=wfs&amp;version=1.1.0&amp;request=GetFeature&amp;typeName=space:buildings&amp;sortBy=year+D&amp;propertyName=year,address</pre>
  <p id="Q4Jd"></p>
  <p id="nNne">Параметр <strong>outputName </strong>позволяет нам определить, в каком формате мы хотим получать ответ. Для нас самым часто используемым будет формат application/json, благодаря которому мы будем получать <a href="https://teletype.in/@rellowy/fsVfkdBwoAu" target="_blank">GeoJSON</a>.</p>
  <hr />
  <p id="peXZ">Оба метода GetCapabilities возвращают <strong>XML. </strong>Я намерено не углубляюсь в их ответы, поскольку GetCapabilities не так часто используется на фронтенде, а если и нужен, то карты, которыми мы будем пользоваться, умеют парсить ответ из коробки. </p>
  <p id="IT6s">Если вам это очень интересно, подробнее можно почитать про <a href="https://www.ogc.org/standard/wms/" target="_blank">WMS</a> и <a href="https://www.ogc.org/standard/wfs/" target="_blank">WFS</a>.</p>
  <hr />
  <p id="zpmY">Geoserver позволяет нам фильтровать объекты как для WMS, так и для WFS, передавая параметр <strong>CQL_FILTER. </strong>Возможностифильтрации мы рассмотрим на практике, так как это тема отдельной статьи, а пока просто важно знать, что оно есть :)</p>
  <p id="mTQQ"></p>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="K9sb" data-align="center"><strong>Этой статьей мы запускаем цикл по разработке карт 🥳</strong></p>
  </section>
  <p id="8CEE"></p>
  <p id="2o2v">На следующем занятии посмотрим, где мы будем хранить наши гео данные, и создадим первый слой.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rellowy/fsVfkdBwoAu</guid><link>https://teletype.in/@rellowy/fsVfkdBwoAu?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><comments>https://teletype.in/@rellowy/fsVfkdBwoAu?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy#comments</comments><dc:creator>rellowy</dc:creator><title>Форматы представления географических объектов</title><pubDate>Mon, 01 May 2023 21:08:22 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/b3/a6/b3a66468-3a76-4511-b221-0e6d68623b19.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/19/0d/190de327-7b11-410e-aef5-997ac373d8f3.png"></img>В предыдущей статье мы затронули такие понятия, как форматы представления географических объектов, а также немного посмотрели на то, какие виды геометрии бывают. Сегодня мы начнем погружаться в детали, будет много технической информации. Надеюсь, вы еще не поджали свои маленькие хвостики. ]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="7Uw8">В предыдущей статье мы затронули такие понятия, как форматы представления географических объектов, а также немного посмотрели на то, какие виды геометрии бывают. Сегодня мы начнем погружаться в детали, будет много технической информации. Надеюсь, вы еще не поджали свои маленькие хвостики. </p>
    <p id="7x5H"><strong>Если вы не читали <a href="https://teletype.in/@rellowy/BJLBcgey_Y-" target="_blank">прошлую статью</a>, настоятельно рекомендую сначала ознакомиться с ней.</strong></p>
  </section>
  <h2 id="2Gx2">Координаты</h2>
  <p id="cPuE"><strong>Координаты</strong> – фундаментальная геометрическая концепция. Свойство «coordinates» объекта геометрия состоит из пары/триплета координат (в случае геометрии типа «Point»), массива координат (объекты типа «LineString» или «MultiPoint»), массива массивов координат (объекты типа «Polygon», «MultiLineString») или многомерного массива координат (объекты типа «MultiPolygon»).</p>
  <p id="AivD">Координаты определяются массивом чисел. Этот массив должен содержать минимум два элемента, но их может быть больше. Порядок элементов должен быть следующим: x, y, z (для данных, находящихся в прямоугольной системе координат - смещение на восток, смещение на север, высота, для данных, находящихся в географической системе координат – долгота, широта, высота). </p>
  <p id="9KAq">Например:</p>
  <pre id="QwSg" data-lang="javascript">[30.315830718468703, 59.95010599732575, 3]</pre>
  <p id="DPDL"><strong>Система координат (СК) или проекция</strong> - определяют, как двумерная спроецированная карта описывает реальные местоположения на Земле с помощью координат.  Нам из этого будет важно понимать, что СК имеет четкую формулу пересчета координат. Основные СК, которым будем оперировать:</p>
  <ol id="UIE4">
    <ol id="heQ7">
      <li id="nFue">WGS 84 или EPSG:4326</li>
      <li id="Gdrt">Меркатор или EPSG:3857</li>
    </ol>
  </ol>
  <p id="SwJb">Пример EPSG:4326</p>
  <pre id="Jgpt" data-lang="javascript">[30.315830718468703, 59.95010599732575]</pre>
  <p id="Yw7x"></p>
  <p id="MU3h">Пример EPSG:3857</p>
  <pre id="lVjp" data-lang="javascript">[3374742.838555017, 8388637.907395536]</pre>
  <p id="ZqBS"></p>
  <p id="Gdn3">В дальнейшем в разных статьях примеры геометрий я буду приводить в разных системах координат. Будем развивать вашу насмотренность, чтобы вы могли с первого взгляда на описание геометрии определять, в какой системе координат она описана. </p>
  <h2 id="TccK">Геометрия</h2>
  <p id="rb5w">Прежде чем приступать к форматам представления, повторим, какие виды геометрий у нас есть, а также узнаете новые.</p>
  <p id="BF8N">Есть три основных вида геометрий, с которыми чаще всего будем сталкиваться на практике.</p>
  <ol id="CDbK">
    <li id="vtlJ">Точка - Point</li>
    <li id="oDNc">Линия - LineString</li>
    <li id="eoJQ">Полигон - Polygon</li>
  </ol>
  <p id="CJrt">Если вы внимательно читали предыдущую статью, особенно описание каждого вида геометрий, наверняка обратили внимание на повторяющуюся фразу <u>&quot;состоит из набора точек&quot;.</u> О чем нам это должно говорить? <strong>Точка является основой любой геометрии. На основе точек, или как их иначе называют, узлов, составляются все остальные геометрии.</strong></p>
  <p id="flkg">Помимо основных видов, существуют еще подвиды - мульти- геометрии, а также геометрия в виде коллекции (geometry collection). </p>
  <p id="LslH">Мульти- геометрия состоит из набора геометрий одного вида, например:</p>
  <ol id="gV75">
    <li id="LADw">MultiPoint - Геометрия, состоящая из нескольких точек</li>
    <li id="a0kD">MultiLineString - Геометрия, состоящая из нескольких линий</li>
    <li id="dbPL">MultiPolygon - Геометрия, состоящая из нескольких полигонов. </li>
  </ol>
  <p id="cIeC">Получается, что, если запустить цикл по массиву координат, можно получить геометрию в ее минимальном представлении. </p>
  <p id="PBAP">А что тогда с коллекцией геометрией? 🤔</p>
  <p id="udDM">Её особенность заключается в том, что, в отличие от мульти- геометрий, в нее можно положить разные виды геометрий. </p>
  <h2 id="GiXw">Форматы представления географических объектов</h2>
  <p id="3Jsz">Чтобы работать с геометрией на фронтенде, обмениваться картографическими данными между системами или просто передавая по API, люди придумали и зафиксировали определенные форматы. На текущий момент для быстрого старта в мир картографии нам хватит двух - <strong>GeoJSON</strong> и <strong>WKT</strong>. </p>
  <p id="Bs63">На деле же форматов гораздо больше - shape, mid/mif, kml и т.п., но подробнее мы их будем разбирать позднее.</p>
  <h2 id="iA5D">GeoJSON</h2>
  <p id="QaYi">Вспомним определение - формат на основе JSON, предназначенный для представления географических объектов с их непространственными атрибутами.</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="IW0H">Так как данный формат сделан на основе формата JSON, то без понимания, как он устроен далеко не уедешь. Прежде чем продолжать изучение картографии, убедитесь, что вы его знаете. А для тех, кто не в курсе, советую <a href="https://habr.com/ru/articles/554274/" target="_blank">полезное чтиво</a>.</p>
  </section>
  <p id="JreB">GeoJSON - четко зафиксированный формат данных. Любое отклонение в сторону грозит риском, что ваши карты его не смогут понять и отобразить. Официально зафиксированный стандарт, можно изучить <a href="https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.8" target="_blank">тут</a>. </p>
  <p id="S65q"><u>Зачем объяснять, если он зафиксирован и можно почитать официальную информацию?</u> </p>
  <ul id="VFRm">
    <li id="U1UL">Не все котята знают английский язык</li>
    <li id="Pgik">Стандарты иногда пишутся очень заумным языком</li>
    <li id="pt3l">Раз уж мы взялись собирать всю информацию в одном месте, давайте соберем и это, тем более rfc не описывает все примеры 🙃</li>
  </ul>
  <p id="E0Hx">Будем идти от простого к сложному - от описания геометрий до описания целого слоя с набором объектов.</p>
  <h3 id="lTaX">Представление геометрий</h3>
  <hr />
  <p id="GTJb">Геометрия описывается в виде объекта, который обязательно должен содержать два поля:</p>
  <ol id="iVuZ">
    <li id="9Zp4"><strong>type</strong> - тип геометрии</li>
    <li id="GW80"><strong>coordinates</strong> - описание координат</li>
  </ol>
  <p id="ecv6">Теперь давайте посмотрим, как выглядят различные типы геометрий в формате geoJSON.</p>
  <p id="UMiO"><strong>Точка - Point</strong></p>
  <pre id="lHeZ" data-lang="javascript">{
   &quot;type&quot;: &quot;Point&quot;,
   &quot;coordinates&quot;: [
         30.315830718468703,
         59.95010599732575
   ]
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/0d926ec49f6be4bdc18b89c44b98e727.js"></script>
    <figcaption>Графическое представление точки на карте</figcaption>
  </figure>
  <hr />
  <p id="HC9u"><strong>Линия - LineString</strong></p>
  <pre id="8eF7" data-lang="javascript">{
   &quot;type&quot;: &quot;LineString&quot;,
   &quot;coordinates&quot;: [
      [30.303325070439058, 59.94495377359024],
      [30.303536318623713, 59.947704454457636],
      [30.31001459629374, 59.950948553926935],
      [30.31445080817707, 59.95271151830221],
      [30.32008409310859, 59.95316987367963],
      [30.323956976498494, 59.95281729318262]
   ]
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/8c289f81a1bfc98885f60dbbb0a1ad7e.js"></script>
    <figcaption>Графическое представление линии на карте</figcaption>
  </figure>
  <hr />
  <p id="Oeor"><strong>Полигон - Polygon</strong></p>
  <p id="u0YG">В простом варианте</p>
  <pre id="1dAC" data-lang="javascript">{
   &quot;type&quot;: &quot;Polygon&quot;,
   &quot;coordinates&quot;: [
      [
         [30.307057121705924, 59.94953811490868],
         [30.32367531225134, 59.953099357880376],
         [30.320436173416283, 59.95658970985352],
         [30.307761282321366, 59.955144255147474],
         [30.307057121705924, 59.94953811490868]
      ]
   ]
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/cd5b7167b478753dd341899f233256af.js"></script>
    <figcaption>Графическое представление полигона на карте</figcaption>
  </figure>
  <p id="4Y3L">Более сложный</p>
  <pre id="2c0T" data-lang="javascript">{
   &quot;type&quot;: &quot;Polygon&quot;,
   &quot;coordinates&quot;: [
      [
         [30.307195, 59.949252],
         [30.32423, 59.952949],
         [30.321053, 59.956903],
         [30.307918, 59.955141],
         [30.307195, 59.949252]
      ],
      [
         [30.311009, 59.954324],
         [30.318907, 59.955442],
         [30.320281, 59.95368],
         [30.311094, 59.952218],
         [30.311009, 59.954324]
      ]
   ]
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/5aa114f050a27c3f2110e38274b9ba4f.js"></script>
    <figcaption>Графическое представление полигона с &quot;дыркой&quot; на карте</figcaption>
  </figure>
  <hr />
  <p id="Zpmi"><strong>Мульти-точка - MultiPoint</strong></p>
  <pre id="IRxp" data-lang="javascript">{
   &quot;type&quot;: &quot;MultiPoint&quot;,
   &quot;coordinates&quot;: [
      [30.260433, 59.932574],
      [30.293057, 59.941431],
      [30.290653, 59.92337]
   ]
}</pre>
  <figure id="G2hP" class="m_original">
    <img src="https://img2.teletype.in/files/19/0d/190de327-7b11-410e-aef5-997ac373d8f3.png" width="643" />
    <figcaption>Графическое представление мульти-точки на карте</figcaption>
  </figure>
  <hr />
  <p id="wy13"><strong>Мульти-линия - MultiLineString</strong></p>
  <pre id="zzyF" data-lang="javascript">{
   &quot;type&quot;: &quot;MultiLineString&quot;,
   &quot;coordinates&quot;: [
      [
         [30.296181, 59.954495],
         [30.312751, 59.964721]
      ],
      [
         [30.295062, 59.955225],
         [30.311982, 59.96558]
      ],
      [
         [30.306481, 59.950025],
         [30.305966, 59.952819],
         [30.308885, 59.95559],
         [30.311761, 59.956708],
         [30.317084, 59.95703],
         [30.320776, 59.956256],
         [30.323609, 59.955075],
         [30.324897, 59.953807]
      ]
   ]
}</pre>
  <figure id="x3ii" class="m_original">
    <img src="https://img1.teletype.in/files/ce/23/ce23fa6e-bb9f-4aef-ac5e-b0b3fd82074c.png" width="740" />
    <figcaption>Графическое представление мульти-линии на карте</figcaption>
  </figure>
  <hr />
  <p id="yafJ"><strong>Мульти-полигон - MultiPolygon</strong></p>
  <pre id="xOYo" data-lang="javascript">{
   &quot;type&quot;: &quot;MultiPolygon&quot;,
   &quot;coordinates&quot;: [
      [
         [
            [30.283822, 59.951443],
            [30.286397, 59.950283],
            [30.288973, 59.952389],
            [30.286483, 59.953248],
            [30.283822, 59.951443]
         ]
      ],
      [
         [
            [30.308976, 59.948607],
            [30.312239, 59.947704],
            [30.317905, 59.948091],
            [30.321253, 59.949896],
            [30.323056, 59.951099],
            [30.322283, 59.952217],
            [30.315072, 59.952217],
            [30.311724, 59.95097],
            [30.308976, 59.948607]
         ]
      ],
      [
         [
            [30.333787, 59.953764],
            [30.33808, 59.953764],
            [30.33808, 59.955698],
            [30.333787, 59.955698],
            [30.333787, 59.953764]
         ]
      ]
   ]
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/e511e703de5324993cb947d3e8024456.js"></script>
    <figcaption>Графическое представление мульти-полигона на карте</figcaption>
  </figure>
  <hr />
  <p id="aoTU"><strong>Коллекция геометрий - GeometryCollection</strong></p>
  <pre id="HbNq" data-lang="javascript">{
   &quot;type&quot;: &quot;GeometryCollection&quot;,
   &quot;geometries&quot;: [
      {
         &quot;type&quot;: &quot;Point&quot;,
         &quot;coordinates&quot;: [30.304941,59.95776]
      },
      {
         &quot;type&quot;: &quot;Polygon&quot;,
         &quot;coordinates&quot;: [
            [
               [30.330697, 59.954623],
               [30.335848, 59.954623],
               [30.335848, 59.95703],
               [30.330697, 59.95703],
               [30.330697, 59.954623]
            ]
        ]
      }
   ]
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/dffe3872d69e463991b2ad6f136d03e3.js"></script>
    <figcaption>Графическое представление коллекции геометрий на карте</figcaption>
  </figure>
  <p id="3tfT">&quot;Вау! Мы нарисовали слой!!!&quot;, - могли подумать вы, и оказались не правы. Мы нарисовали всего лишь геометрию, состоящую из двух разных простых геометрий. Мы даже не нарисовали объект, так как у нас нет набора атрибутов.</p>
  <hr />
  <h3 id="mcBq">Представление объектов</h3>
  <hr />
  <p id="NlD8">С геометрией все понятно, но ведь у объекта есть атрибуты. Куда же их девать?</p>
  <p id="iA1v">Чтобы описать объект вместе с его атрибутами, в geoJSON сделали сущность <strong>Feature. </strong></p>
  <p id="b3rr">Feature обязательно должен иметь следующие поля:</p>
  <ol id="TL7V">
    <li id="zPgW"><strong>type</strong> - тип, значение <u>Feature</u></li>
    <li id="F3fP"><strong>geometry</strong> - описание геометрии</li>
    <li id="8vTi"><strong>properties</strong> - атрибуты объекта в виде JSON объекта.</li>
  </ol>
  <p id="VlMA">Если объект содержит идентификатор, он может быть указан в виде отдельного поля<strong> id.</strong></p>
  <p id="Szgb">Если объект не содержит атрибутов, то поле <u><strong>properties</strong> должно быть установлено в значение пустого объекта</u>. Отсутствие данного поля будет означать, что описание объекта является не валидным.</p>
  <pre id="AbZQ" data-lang="javascript">{
   &quot;type&quot;: &quot;Feature&quot;,
   &quot;properties&quot;: {
      &quot;shape&quot;: &quot;Circle&quot;,
      &quot;radius&quot;: 192.8759203950539,
      &quot;name&quot;: &quot;Просто круг в центре города&quot;
   },
   &quot;geometry&quot;: {
      &quot;type&quot;: &quot;Point&quot;,
      &quot;coordinates&quot;: [30.304941,59.95776]
   },
   &quot;id&quot;: &quot;8c2c17eb-0c4a-4ed5-bab9-d00ae8289303&quot;
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/4276e07ac490dfbaf75d2108c891651c.js"></script>
    <figcaption>Графическое представление объектаа на карте (при клике на объект можно посмотреть его атрибуты)</figcaption>
  </figure>
  <p id="ik4l">А что с GeometryCollection? Все ровно также, как и с обычной геометрий. Поле geometry получает в виде значения описание GeometryCollection. Однако с точки зрения карты получится, что все ваши геометрии будут иметь одинаковый набор атрибутов, соответственно. Если вы хотите иметь разный атрибутивный состав, то у вас есть два пути описания:</p>
  <ol id="SPXI">
    <li id="1vaR">Отказаться от GeometryCollection и поместить каждую геометрию в свой Feature, получив тем самым несколько разных объектов</li>
    <li id="T56k">Создать атрибут объекту Feature, который содержал бы значение массива объектов JSON, описывающих каждую геометрию отдельно</li>
  </ol>
  <hr />
  <h3 id="9nVa">Представление слоя</h3>
  <hr />
  <p id="0gfq">Feature - это прекрасно, но мы хотим получать слой! </p>
  <p id="oDG1">И на этот случай вам приходит сущность <strong>FeatureCollection. </strong>Эта сущность является самой верхоуровневой. Выше уже ничего не нет.</p>
  <p id="gUBf">FeatureCollection должен иметь следующие поля:</p>
  <ol id="PGFz">
    <li id="X5cv"><strong>type</strong> - тип, значение <u>FeatureCollection</u></li>
    <li id="RPy0"><strong>features</strong> - массив <u>объектов Feature</u></li>
  </ol>
  <p id="3VSn">Если объектов в слое еще нет, features должен быть объявлен как пустой массив.</p>
  <p id="fsSH">В дальнейшем мы будем работать с Geoserver и получать слой разными способами. Забегу немного вперед. Если мы посмотрим на представление FeatureCollection, которое будет отдавать Geoserver, то увидим, что, помимо двух обязательных полей, он отдает еще ряд дополнительных, например, totalFeatures, crs и другие. Стандарт geoJSON позволяет расширять описание, добавляя дополнительные поля, если они необходимы. Мы даже можем добавить дополнительную геометрию, например, основная геометрия - полигон, а нам нужна центральная точка полигона. Однако стандарт говорит о том, что поле crs с указанием системы координат больше не используется, соответственно, валидаторы считают такой geoJSON невалидным</p>
  <p id="Sbh4">Geoserver отдает дополнительные поля скорее для упрощения жизни разработчику. Например, он позволяет делать пагинацию, запрашивая слой с limit и offset, как это делали бы мы в SQL. За счет передачи дополнительных полей мы четко можем понять, сколько всего объектов слое, а сколько мы получаем.</p>
  <pre id="iC1r" data-lang="javascript">{
    &quot;type&quot;: &quot;FeatureCollection&quot;,
    &quot;features&quot;: [{
        &quot;type&quot;: &quot;Feature&quot;,
        &quot;properties&quot;: {
            &quot;shape&quot;: &quot;Circle&quot;,
            &quot;radius&quot;: 192.8759203950539,
            &quot;name&quot;: &quot;Просто круг в центре города&quot;
        },
        &quot;geometry&quot;: {
            &quot;type&quot;: &quot;Point&quot;,
            &quot;coordinates&quot;: [30.304941, 59.95776]
        },
        &quot;id&quot;: &quot;8c2c17eb-0c4a-4ed5-bab9-d00ae8289303&quot;
    }, {
        &quot;type&quot;: &quot;Feature&quot;,
        &quot;properties&quot;: {
            &quot;shape&quot;: &quot;Rectangle&quot;,
            &quot;name&quot;: &quot;Unnamed Layer&quot;
        },
        &quot;geometry&quot;: {
            &quot;type&quot;: &quot;Polygon&quot;,
            &quot;coordinates&quot;: [
                [
                    [30.330697, 59.954623],
                    [30.335848, 59.954623],
                    [30.335848, 59.95703],
                    [30.330697, 59.95703],
                    [30.330697, 59.954623]
                ]
            ]
        },
        &quot;id&quot;: &quot;a6ccfde2-6ab9-4254-a051-c7a5faa4d594&quot;
    }, {
        &quot;type&quot;: &quot;Feature&quot;,
        &quot;properties&quot;: {
            &quot;shape&quot;: &quot;Line&quot;,
            &quot;name&quot;: &quot;Unnamed Layer&quot;
        },
        &quot;geometry&quot;: {
            &quot;type&quot;: &quot;LineString&quot;,
            &quot;coordinates&quot;: [
                [30.301336, 59.969962],
                [30.30434, 59.96906],
                [30.308891, 59.969489]
            ]
        },
        &quot;id&quot;: &quot;925627f4-f015-419f-8cf5-b84f1ec7d408&quot;
    }],
    &quot;totalFeatures&quot;: 10,
    &quot;numberMatched&quot;: 10,
    &quot;numberReturned&quot;: 3,
    &quot;timeStamp&quot;: &quot;2023-05-01T19:42:10.965Z&quot;,
    &quot;crs&quot;: {
    	&quot;type&quot;: &quot;name&quot;,
    	&quot;properties&quot;: {
    		&quot;name&quot;: &quot;urn:ogc:def:crs:EPSG::4326&quot;
    	}
    }
}</pre>
  <figure>
    <script src="https://gist.github.com/rellowy/c8a304eef534f5736fd9a2f7c2c78eff.js"></script>
    <figcaption>Графическое представление слоя на карте</figcaption>
  </figure>
  <hr />
  <h3 id="DnGS">Инструменты</h3>
  <p id="8QTJ"><a href="https://geojson.io/" target="_blank">Быстрый просмотр и редактор геометрий </a></p>
  <p id="jgQU"><a href="https://geojsonlint.com/" target="_blank">Валидация geoJSON</a></p>
  <hr />
  <h2 id="j6xS"></h2>
  <h2 id="6jj8">WKT - <strong>Well-known text</strong></h2>
  <p id="tMwH">Еще один формат представления географических объектов. Не привязан ни к каким форматам, позволяет описывать геометрию в виде строки. Какого-то конкретного стандарта я найти не смог, однако на сайте IBM есть вполне четкое <a href="https://www.ibm.com/docs/en/db2-warehouse?topic=formats-well-known-text-wkt-format" target="_blank">описание</a>. </p>
  <p id="tGOV"><u>Неужели GeoJSON не хватает? </u></p>
  <p id="Ba11">Да, не хватает. GeoJSON хоть и позволяет описать весь слой, однако итоговое описание получается очень громоздким, что нам не подходит под некоторые задачи.</p>
  <p id="B7Ku">В отличие от GeoJSON, WKT не позволяет описать весь слой, не позволяет описывать объекты слоя, т.е. никаких атрибутов положить в текстовое описание мы не можем.</p>
  <p id="YTpO"><u>Так для чего же нам тогда пригодится этот формат?</u></p>
  <p id="GB4w">Поскольку в нашей практической части мы будем использовать открытое ПО, ГИС Geoserver, реализующий стандарт OGC, он будет накладывать на нас определенные ограничения.</p>
  <p id="rBHF">В некоторый момент мы придем к тому, что заходим отфильтровать слой, получив определенный набор объектов. В Geoserver мы можем сделать это двумя путями:</p>
  <ol id="NB4o">
    <li id="YBJs">Отправить запрос, сформировав определенного формата XML</li>
    <li id="aVMV">Добавить query параметр к запросу</li>
  </ol>
  <p id="pYbd">Я предпочитаю использовать второй вариант, так как его понимают большинство.</p>
  <p id="smMj">Query параметр сам по себе уже накладывает на нас ограничение. Передавать JSON таким способом плохая идея, тут нам на помощь как раз и приходит WKT.</p>
  <p id="LTf7"></p>
  <p id="jion">Закончили минутку забегания вперед, давайте смотреть, как же описывать геометрию в данном формате.</p>
  <p id="uQSy">WKT позволяет нам описать геометрию в виде строки определенного формата.</p>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="ovF5" data-align="center">СИСТЕМА_КООРДИНАТ;ТИП_ГЕОМЕТРИИ(КООРДИНАТЫ)</p>
  </section>
  <p id="vFqY">Координаты (долгота и широта) разделяются пробелом. Пары координат разделяются запятой.</p>
  <p id="xPHe">Посмотрим на примерах, как это выглядит.</p>
  <h3 id="NgVL"><strong>Точка</strong></h3>
  <p id="kQVt"><strong>Пустая точка</strong></p>
  <pre id="htUP" data-lang="javascript">POINT EMPTY</pre>
  <hr />
  <p id="mwW1"><strong>Точка с координатами</strong></p>
  <pre id="isSl" data-lang="javascript">SRID=4326;POINT(30.330697 59.954623)</pre>
  <hr />
  <p id="TDnc"><strong>Точка с высотой</strong></p>
  <pre id="oJ6p" data-lang="javascript">SRID=4326;POINT(30.330697 59.954623 3)</pre>
  <hr />
  <p id="Xrqn"><strong>Линия</strong></p>
  <p id="CxEY"><strong>Пустая линия</strong></p>
  <pre id="mkMx" data-lang="javascript">LINESTRING EMPTY</pre>
  <hr />
  <p id="8nQp"><strong>Линия с координатами</strong></p>
  <pre id="zCNw" data-lang="javascript">SRID=4326;LINESTRING (30.303325070439058 59.94495377359024, 30.303536318623713 59.947704454457636, 30.31001459629374 59.950948553926935, 30.31445080817707 59.95271151830221, 30.32008409310859 59.95316987367963, 30.323956976498494 59.95281729318262)</pre>
  <hr />
  <p id="FguJ"><strong>Полигон</strong></p>
  <p id="YsoT"><strong>Простой полигон</strong></p>
  <pre id="jije" data-lang="javascript">SRID=4326;POLYGON ((30.307057121705924 59.94953811490868, 30.32367531225134 59.953099357880376, 30.320436173416283 59.95658970985352, 30.307761282321366 59.955144255147474, 30.307057121705924 59.94953811490868))</pre>
  <hr />
  <p id="fqcc"><strong>Полигон с &quot;дыркой&quot;</strong></p>
  <pre id="UoAQ" data-lang="javascript">SRID=4326;POLYGON ((30.307195 59.949252, 30.32423 59.952949, 30.321053 59.956903, 30.307918 59.955141, 30.307195 59.949252), (30.311009 59.954324, 30.318907 59.955442, 30.320281 59.95368, 30.311094 59.952218, 30.311009 59.954324))</pre>
  <hr />
  <p id="u6qQ"><strong>Коллекция геометрий</strong></p>
  <pre id="n3OS" data-lang="javascript">GEOMETRYCOLLECTION (POINT (30.304941 59.95776), POLYGON ((30.330697 59.954623, 30.335848 59.954623, 30.335848 59.95703, 30.330697 59.95703, 30.330697 59.954623)))</pre>
  <hr />
  <h3 id="Ywtu">Инструменты</h3>
  <p id="gErt"><a href="https://geojson-to-wkt-converter.onrender.com/" target="_blank">Online конвертер geoJSON в wkt</a></p>
  <hr />
  <p id="pGSO">Данных знаний о геометрии и ее форматах представления на текущий момент нам хватит, чтобы начать решать базовые картографические задачи. В будущем мы будем рассматривать и другие форматы представления.</p>
  <p id="IiQO">В следующей статье мы начнем разбирать Geoserver и затронем стандарт OGC.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rellowy/40XGxAGqwfQ</guid><link>https://teletype.in/@rellowy/40XGxAGqwfQ?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy</link><comments>https://teletype.in/@rellowy/40XGxAGqwfQ?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rellowy#comments</comments><dc:creator>rellowy</dc:creator><title>Словарь терминов</title><pubDate>Sat, 29 Apr 2023 15:42:40 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/19/4e/194e396d-1e8d-4a2d-a2cb-d7b2a7da65a2.png"></media:content><category>База</category><description><![CDATA[Котята, садимся, начинаем наше занятие.  Сегодня мы начнем наше изучение дивного мира картографии. Для того, чтобы нам с вами было легче общаться и находить общий язык, необходимо познакомиться с основными терминами. Терминов достаточно много, знать прям наизусть определения вовсе необязательно, достаточно четко понимать смысл. Буду стараться описывать максимально простыми словами, чтоб было легче запоминать.]]></description><content:encoded><![CDATA[
  <p id="mAr6">Котята, садимся, начинаем наше занятие.  Сегодня мы начнем наше изучение дивного мира картографии. Для того, чтобы нам с вами было легче общаться и находить общий язык, необходимо познакомиться с основными терминами. Терминов достаточно много, знать прям наизусть определения вовсе необязательно, достаточно четко понимать смысл. Буду стараться описывать максимально простыми словами, чтоб было легче запоминать.</p>
  <p id="eAcI">Итак, поехали!</p>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <ol id="RGeR">
      <li id="3zMM"><strong>Геоинформационная система (ГИС, </strong>не путать с <u>Государственной ИС</u><strong>)</strong> - информационная система, предназначенная для сбора, хранения, анализа  и графической визуализации пространственных данных и связанной с ними информации.</li>
      <li id="lWwg"><strong>Координаты</strong> - величины, определяющие положение объекта в пространстве (на плоскости).</li>
      <li id="u25O"><strong>Система координат (СК) или проекция</strong> - определяют, как двумерная спроецированная карта описывает реальные местоположения на Земле с помощью координат.  Нам из этого будет важно понимать, что СК имеет четкую формулу пересчета координат. Основные СК, которым будем оперировать:</li>
      <ol id="heQ7">
        <li id="gfAV">WGS 84 или EPSG:4326</li>
        <li id="egeX">Меркатор или EPSG:3857</li>
      </ol>
      <li id="PRcj"><strong>Объект</strong> - сущность, содержащая в себе геометрию и ее атрибутивный состав. <u>Объект без геометрии существовать не может.</u></li>
      <li id="u70b"><strong>Атрибуты объекта (атрибутивный состав)</strong> - значения, описывающие характеристики объектов. </li>
      <li id="F03g"><strong>Геометрия объекта</strong> - одна или несколько координат.</li>
      <ol id="7Unw">
        <li id="VJCX">Все координаты геометрии объединяет единая система координат. <u>Координаты одной геометрии не могут существовать в разных СК</u>.</li>
        <li id="SJY1">Имеет различные виды:</li>
        <ol id="8ej6">
          <li id="CwBQ"><strong>Точка</strong> - состоит всего лишь из одной координаты. Не имеет длины, периметра и площади.</li>
          <li id="ITzY"><strong>Линия</strong> - состоит из набора точек, не соединенных в замкнутый контур. Не имеет площади, но можно посчитать длину.</li>
          <li id="oJc5"><strong>Полигон</strong> - состоит из набора точек, которые соединены в замкнутый контур (начальная и конечная координаты совпадают). Иногда в полигоне могут вырезать некоторый участок (&quot;дырку&quot;). В таком случае геометрия будет похожа на коллекцию из нескольких полигонов. Можно посчитать площадь и длину контура.</li>
          <li id="bVED"><strong>Круг</strong> - определяется в виде координаты точки с определенным радиусом. Имеет радиус, можно посчитать площадь и длину окружности.</li>
        </ol>
      </ol>
      <li id="0JIS"><strong>Коллекция геометрий (GeometryCollection)</strong> - геометрия объекта, состоящая из нескольких разных геометрий. </li>
      <li id="yA04"><strong>Экстент (Extent)</strong> - выводимая на экран прямоугольная область карты или географический охват данных.</li>
      <li id="uVwN"><strong>GeoJSON </strong>- формат на основе JSON, предназначенный для представления географических объектов с их непространственными атрибутами. </li>
      <li id="Ha7A"><strong>WKT </strong>- еще один формат представления географических объектов. Объект представляется в виде строки определенного формата: СК;ТИП_ГЕОМЕТРИИ(КООРДИНАТЫ)</li>
      <li id="Typz"><strong>Слой</strong> - визуальное представление набора географических данных (объектов). </li>
      <li id="udfw"><strong>Групповой слой </strong>- несколько слоев, объединенных в группу.</li>
      <li id="wUOV"><strong>Растровый слой</strong> - содержит данные в виде фрагментов растровых изображений, приведенных в одну проекцию и подготовленных для каждого из уровней детализации карты. Растровый слой в привычном виде состоит из набора картинок, размером 512x512, но так бывает не всегда. Растровый слой может быть получен в виде одной большой картинки по указанному экстенту.</li>
      <li id="Ulot"><strong>Векторный слой </strong>- слой, содержащий данные об объектах. Такой слой накладывается на карту в виде геометрий с рядом параметров. Чаще всего получаем слой в формате GeoJSON.</li>
      <li id="OJV3"><strong>Подложка </strong>- <u>всегда только растровый слой</u>, лежащий в основе карты. Такой слой может быть собран из множества других слоев, но очень часто за основу используется OpenStreetMap (OSM).</li>
      <li id="B3Pa"><strong>OpenStreetMap (OSM) </strong>- открытый интернет проект, в который любой желающий может заносить картографические данные. Благодаря такой возможности и трудам людей, OSM содержит огромное количество гео-данных, используемых даже крупными компаниями (Яндекc, Google, ...etc). OSM предоставляет не только подложку, но и базу объектов.</li>
      <li id="gOkj"><strong>Легенда</strong> - свод условных знаков и пояснений к объектам слоя. </li>
      <li id="DTBM"><strong>Масштаб (Scale)</strong> - отношение расстояния на карте и соответствующего расстояния на местности. Обычно выражается в виде дроби или отношения. Масштаб 1:100000 означает, что одна единица на карте соответствует 100000 этих же единиц измерения на местности.</li>
      <li id="CGlE"><strong>Панель инструментов</strong> - графический интерфейс пользователя с кнопками, позволяющими выполнять программные команды.</li>
      <li id="0ZgO"><strong>Стиль</strong> - оформление отображения объектов.</li>
    </ol>
  </section>

]]></content:encoded></item></channel></rss>