Клуб Народной карты

Рисование кругов и правильных многоугольников

Alexxegorov
26 октября 2015, 14:04

В начале месяца я обещал выложить инструкцию, как рисовать круги. И вот я наконец разродился статьей

Для рисования потребуется приложения AutoHotkey и специальный скрипт для него. Приложение предназначено для выполения макросов и привязки их к сочетаниям клавиш.
Автором подхода и скрипта является Falcon. Я переработал скрипт, чтобы его можно было применять без масштабирования и переноса полученного круга. Что позволило рисовать дороги и избавило от проблемы, когда перестало работать масштабирование с сохранением пропорций.

Предварительные шаги:

1) Скачать и установить приложения AutoHotkey

2) Скачать скрипт.

Не могу гарантировать долговременное хранение скрипта в общем доступе, поэтому прикладываю его код здесь. Достаточно сохранить этот код в текстовом файле с расширением .ahk

/*
Alt+R рисование круга на основе трех точек
Alt+P Правильный многоугольник с заданным количеством вершин
Alt+ Left mouse button click - двойное нажатие для простого удаления вершин
*/
GetSegmentLength(x1, y1, x2, y2)
{
return Sqrt((x1 - x2)**2 + (y1 - y2)**2)
}
GetRadius(a, b, c)
{
p := (a+b+c)/2
s := Sqrt(p*(p-a)*(p-b)*(p-c))
rs := (a*b*c)/(4*s)
return rs
}
GetCenter(x1, y1, x2, y2, x3, y3, ByRef x0, ByRef y0)
{
A1 := x2 - x1
B1 := y2 - y1
C1 := (x2-x1)*(x2+x1)/2 + (y2-y1)*(y2+y1)/2
A2 := x3 - x1
B2 := y3 - y1
C2 := (x3-x1)*(x3+x1)/2 + (y3-y1)*(y3+y1)/2
x0 := (C1*B2 - C2*B1)/(A1*B2 - A2*B1)
y0 := (A1*C2 - A2*C1)/(A1*B2 - A2*B1)
}
DrawCircle(x, y, r, n)
{
pi = 3.1415926535898
beta0 := pi ; начальный угол (точнее угол последней точки)
loop, %n%
{
beta := 2.*pi/n+beta0 ; угол в радианах
px := -1 * sin(beta)*r+x ; если поменять синус и косинус местами, будет рисовать в другую сторону
py := -1 * cos(beta)*r+y
click, %px%, %py%
sleep, 150
beta0 := beta
}
}
;Рисование кругов на основе трёх точек
#IfWinActive Народная карта Яндекса
!r::
n = 30 
r = 250
MouseGetPos, x1, y1 
MsgBox Вторая точка
MouseGetPos, x2, y2 
MsgBox Третья точка
MouseGetPos, x3, y3
InputBox, n, Количество вершин
x0 := 0 
y0 := 0
as := GetSegmentLength(x1, y1, x2, y2)
bs := GetSegmentLength(x1, y1, x3, y3)
cs := GetSegmentLength(x3, y3, x2, y2)
r := GetRadius(as, bs, cs)
с := GetCenter(x1, y1, x2, y2, x3, y3, x0, y0)
DrawCircle(x0, y0, r, n)
Send ^M
return
;Рисование правильных многоугольников
#IfWinActive Народная карта Яндекса
!p::
n = 64 
r = 250  
InputBox, n, Количество вершин
DrawCircle(860, 540, r, n)
return
;Двойной клик для удаления точки
#IfWinActive Народная карта Яндекса
LAlt & LButton::
click
click
return

3) Включить скрипт в AutoHotkey, запустив файл скрипта. Убедитесь, что при этом включена английская раскладка, иначе получите сообщения об ошибке. (это решение на коленке, просьба не судить за подобные дурацкие нюансы)

Запущенный скрипт ожидает определённые сочетания клавиш, чтобы начать свою работу. Сочетания клавиш срабатывают, если активна вкладка в браузере с Народной картой.

Как нарисовать круг (многоугольник)

Круг рисуется по трём точкам. В процессе нужно будет указать три точки на окружности, по которым дальше скрипт построит полный круг. Этот алгоритм подходит как для отрисовки зданий и территорий, так и для дорог, и сложных контуров. 
Далее по пунктам:

1) Открыть на карте место, где нужно нарисовать круг. Круглый объект должен полностью вмещаться на экране. Элементы интерфейса не должны его заслонять. Чем больше будет масштаб, тем более детально и плавнее можно нарисовать круг.

2) В меню Создать выбрать контур или линию, которые надо нарисовать. По сути, скрипт будет просто ставить точки за вас. 

3) Отключить Режим залипания. Если его оставить включенным, скрипт может попортить форму круга, пытаясь автоматически подровнять углы.

4) Навести курсор на любую точку на окружности, которую предстоит описать, и нажать сочетание клавишь Alt+R. Скрипт запомнит первую точку окружности. Важно после этого не двигать карту.

5) Скрипт предложит указать вторую точку. Навести курсор на любую вторую точку на окружности (но лучше на некотором расстоянии от первой) и нажать Enter. Кликать мышкой не надо.

6) Скрипт запросит указать третью точку. Поступаем аналогично. Я стараюсь указывать три точки равномерно, как если бы они формировали почти равносторонний вписанный треугольник в круге.

Скрипт запомнил все три точки. Теперь он предложит указать количество вершин. Можно указать конкретное количество вершин, чтобы создать правильный многоугольник. Чем больше количество вершин, тем плавнее будет круг. Чем больше размер круга на карте, тем больше можно указать вершин. Однако, если переборщить с количеством вершин, скрипт может накосячить. 

7) Ввести число вершин, нажать и нажать OК или Enter. Скрипт начнёт рисовать круг. Важно ему не мешать, а именно не трогать мышку и клавиатуру.

 

8) Дождаться, когда скрипт расставит все точки. Иногда скрипт пропускает последнюю вершину. Лекарство от этого - отрисовать с меньшим количеством вершин. Однако, в большинстве случае достаточно самостоятельно на глаз поставить последнюю точку. Так быстрее. Если создавали новый сложный контур, замкнуть его нужно самостоятельно. Дорогу замкнуть не получиться. Последний сегмент надо дорисовать после того как полученная линия будет поделена как минимум на две части.

9) Сохранить объект.

Пара дополнительных возможностей скрипта:

  • По Alt+P запускается первоначальный алгоритм, который написал Falcon. Для него достаточно задать количество вершин, фигура будет нарисована посередине экрана с фиксированным диаметром.
  • При нажатом Alt один клик левой кнопки мыши работает как двойной клик. Я это использую, когда нужно удалить много точек за раз. Немного упрощает задачу

Нюансы и потенциальные косяки:

  • Если при запуске файла со скриптом валяться ошибки типа "hotkey doesn't exist in current keyboard layout", убедитесь, что включена английская раскладка
  • Код скрипта ориентируется на название окна с Народной картой, чтобы не срабатывать в других приложениях и на других сайтах. Если Яндекс поменяет название страницы, нужно будет заменить его везде в скрипте, чтобы он снова заработал.
  • Точки контура намеренно расставляются с задержкой, чтобы Народная карта успевала корректно отрабатывать нажатия. Однако, если компьютер не столь шустрый или занят параллельно более важными делами, возможно, потребуется увеличить задержку. Найдите в коде строку "sleep, 150" и увеличьте значение задержки.
  • Первоначальный алгоритм по Alt+P заточен на размер окна и разрешение экрана 1920х1080. Если у вас иное разрешение экрана или нестандартный размер окна, придётся подправить скрипт в этом месте (250 - радиус окружности, 860 и 540 - центр окружности по горизонтали и вертикали соответственно)
    r = 250  
    InputBox, n, Количество вершин
    DrawCircle(860, 540, r, n)
48 комментариев

Отлично! Спасибо.

По мне вполне достаточно работы алгоритма Falcon. Круг уже ровный и его можно спокойно масштабировать и переносить штатными средствами.

Еще понравилась возможность удалять узлы по одинарному клику с Alt.

Если разработчики карты наконец-то вернут масштабирование с сохранением пропорций, то алгоритм Falcon будет основным для рисования контуров, так как он гораздо проще в использовании. Но вот круговое движение им нарисовать так просто не получится.  

...ага, и газоны таким образом не нарисуешь. Приходится сначала рисовать здание, а по нему обводить газон.

Спасибо вам, всё получилось)

Бакулин Станислав
26 октября 2015, 18:01

Спасибо!

В Яндекс Браузере работает? У меня после указания третьей точки начинается котовасия на компе - запускаются различные приложения, переключаются окна и пр.

Работает. Что-то не то наверное делаешь.

 

Скрипт эмулирует клики мышкой, как если бы это делал пользователь. А пользователь от браузера не зависит :)
Котовасия может начинаться, если после указания какой-либо из точек подвинуть карту (тогда скрипт будет тыкать вне карты и запускать приложения) или если после запуска процесса рисования открылось поверх иное приложение, тогда скрипт будет тыкать по этом приложению.
Попробуйте повторить всё аккарутно, следя за тем, чтобы карта не двигалась и другие приложения не мешали. 

Да, именно из-за подвижек карты "котовасилось". Спасибо!

Полезная вещь. Спасибо за такое изобретение :)

А выключить как?

Что выключить?

Да и вообще, как включить? Включаю - раскладка меняется на русский и не убирается.

Как включить указано в инструкции первым делом.
Приложение и скрипт на раскладку не должны влиять. 

А куда скрипт вписывать? Из какой папки он его берёт?

Пожалуйста, прочитайте инструкцию. Там всё описано.
Достаточно скачать файл со скриптом и запустить его двойным кликом. Перед этим, конечно же скачать и установить приложение AutoHotkey. 

Script lines most recently executed (oldest first).  Press [F5] to refresh.  The seconds elapsed between a line and the one after it is in parentheses to the right (if not 0).  The bottommost line's elapsed time is the number of seconds since it executed.

 

---- C:\Users\user\Downloads\Circles and polygons (1).ahk

008: {

013: {

021: {

033: {

050: Return (42.54)

 

Press [F5] to refresh.

 

 

Что это означает?

Значит ровно то, что там написано, а именно список команд, который выполнил скрипт. Вам не нужно это окно. Просто закройте его.

Скриптом здорово рисовать новые объекты и перерисовывать объекты не имеющие пересечения с другими. А вот как скруглить криво отрисованый круговой перекрёсток, состоящий из множества рёбер? Или только удалять и снуля? Не имея прав на удаление дорог, практически без шансов?

Удалять и с нуля. Так в любом случае будет быстрее и аккуратнее.
А вообще, если нужна только часть окружности, можно отрисовать весь круг и потом лишние точки удалить. Но это муторно.

Выражаю огромную благодарность Вам, Alexxegorov, а также пользователю Falcon. Спасибо Вам обоим за упрощение жизни пользователей, рисующих окружности!

да не за что

Ах, и кстати. Везде узнаю это место. Это Калининград.))

Да, сделал скриншоты, когда делал там газон по вашей просьбе :)

Дайте ссылку на русскоязычную версию программы!

Поищите, пожалуйста, сами. Мы с вами в равной ситуации: я не знаю, есть ли она вообще в природе. 
Для того, чтобы рисовать круги, вам не нужно непосредственно пользоваться этой программой. Достаточно, запустить скрипт. Он автоматически откроется в этой программе в фоне. На этом и ограничивается ваше взаимодействие с AutoHotkey. Вы можете рисовать круги вообще не заглядывая в программу.

Скрипт, конечно, предоствляется как есть, то есть я не подписывался оказывать всестороннюю поддержку. Доработку оставляю на своё усмотрение.
Но если вы всё-таки заинтересованы решить проблему, опишите шаги, которые делаете (так, чтобы можно было проверить, совадают ли они с инструкцией), и что при этом происходит. Можете кинуть текст из окна программы AutoHotkey, куда она пишет все последние действия скрипта. 

А есть другие "программы-читатели" скриптов такого формата?

Ведь формат "Ank", да?

Расширение .ahk - аббревиатура от AutoHotkey. Если хотите - поищите, есть ли другие приложения, совместимые со скриптами для AutoHotkey. Но вам это не поможет. Вряд ли дело в приложении.

Зачем нужна русская то? В меню лазить нет необходимости..

Даа, помню как Falcon со мной поделился своим творчеством мнадцать лет назад)). С тех пор и допиливаю скрипт для НЯК. Правда помнится мне он просил не распространять его особо.. Ну да ладно, я даже рад что теперь со всеми можно будет делиться скриптом. Я себе уже не представляю рисование без AHK.

 

Немного по теме из первого поста:

 

Редим включения/выключения скрипта (добавить в начале):

Suspend; скрипт запустится в выключенном состоянии

RWin::Suspend; вкл / выкл- RWin (правая кнопка Windows)

F12::Reload; перезагрузка скрипта- F12

 

Для того, чтобы работало при любой раскладке:

!vk52 - Alt+R

!vk50 - Alt+P

В моей версии скрипта очень много наработок по созданию и редактированию объектов, а так же управление панелью модерации.

Раз пошла такая телега, то допилю свою версию скрипта для массового пользователя и выложу позднее. Сейчас до сих пор переделываю под новый интерфейс)).

У меня ещё есть своё для быстрого удаления (для модераторов).
И хоткеи для быстрого доступа к круглым кнопкам.
 

Из идей: отрисовка части окружности опять же по трём точкам, но только от начально до конечной точки, чтобы проще рисовать сектора. 

Кстати, скрипт-то работает при любой раскладке. Главное - запустить при английской.

(+1) десять раз!

Комментарий удалён

Если вы вызываете команду Alt+P, то да, она зависит от разрешения экрана. Об этом прямо написано в инструкции и дана подсказка, где нужно подправить скрипт, чтобы заработало корректно на другом разрешении. В качестве центра укажите половину ширины и высоты экрана. Возможно придется уменьшить радиус круга. 
 

Комментарий удалён

Странно. Попробуйте заменить в скрипте !r на !vk52-!r

Не забудьте после сохранения изменений перезагрузить срикпт (левый клик по иконки AutoHotkey в панели задач и выбрать в меню Reload This Script)

ВластилинПолмира
8 ноября 2015, 15:40

А не будет ли лучше заменить количество вершин на расстояние между вершинами?
При больших разиусах сложно прикинуть нужно еколичество чтобы точки были через 2 или через 5 метров.
И как наглаз прикидывается это количество точек?

Расстояния же ещё как-то высчитать надо, исходя из масштаба карты. Попробуйте одно количество точек. Не понравилось - задайте другое количество. Какой-то особой точности здесь не нужно. Приемлемый результат получается на большом диапазоне значений. 

ВластилинПолмира
9 ноября 2015, 10:58

Сейчас заметил, что круг выглядит округлям при определенном количестве точек для любого радиуса.
Я смотрел 24 точки на окружность диаметром 64 м.
Между узлами получается 10м, но это не мешает восприятию округлости.
Достаточно рекомендавать оптимальное количество узлов, чтобы не было 90 при тех же 64 м диаметра.

Количество точек дожлно зависеть не от размера объекта в метрах, от того, какого размера круг у вас на экране получается.  Один и тот же объект можно отрисовать на разном масштабе карты и на экране круг при этом будет разного размера.

В картинках-примерах круг рисуется практически максимально большой в окне браузера, которое полностью развернуто на экране FullHD. Используется 60 точек. И этого вполне достаточно. Для меньших объектов нужно брать меньше точек.

Раз функционал полезный, почему бы не внести его как инструмент в сами НЯК?

Напишите, пожалуйста, эту просьбу в фичреквесты

Если скрипт перестал работать, скачайте его заново. Изменился заголовок окна, на которое он ориентируется. Поправил искомый заголовок в скрипте.
Alexxegorov,
Можно же просто строку в коде эту удалить.
Олег Чечулин
9 июля 2016, 09:30
Если Вы хотите всерьёз заниматься компьютерной графикой, забудьте про формулу Герона для вычисления площадей треугольников - s := Sqrt(p*(p-a)*(p-b)*(p-c))
Этот метод использует 4 операции извлечения корня (3 - при определении длин сторон a,b,c, и ещё одна - непосредственно в формуле). Это очень долго и даёт большую погрешность.
Для вычисления площади треугольника по координатам его вершин нужно пользоваться следующей формулой, которая содержит только сложения и умножения целочисленных величин (ну и ещё сдвиг вправо на один бит и проверку/смену знака, чем можно пренебречь), соответственно, работает быстрее и точнее:
s:=abs((x1-x3)*(y2-y3)-(x2-x3)*(y1-y3))/2
(abs - это абсолютная величина, я не знаю, как она обозначается в данном скриптовом языке).
В данном конкретном скрипте, конечно, это и не очень критично, но в более серьёзных приложениях выигрыш существенный (как по скорости, так и по точности).
Олег Чечулин
9 июля 2016, 09:38
Ну и радиус описанной окружности тоже лучше считать по-другому:
r := x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2)