Рисование линий и закрашивание областей в табличном документе 1С. Техническая реализация

17.03.25

Разработка - Математика и алгоритмы

Графические алгоритмы рисования линий и закрашивания областей в 1С. Подробное описание.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование Бесплатно
Рисование линий и закрашивание областей в табличном документе 1С. Техническая реализация:
.epf 12,97Kb
3
3 Скачать бесплатно

Недавно я разместил пример обработки, которую я написал для тестов и своего собственного развлечения: Рисование линий и закрашивание областей в табличном документе 1С. В комментариях спросили о технической реализации, рассказываю. 

 

Рисование линий

Первая задача - как выделить фоном ячейки в табличном документе 1С, так чтобы они образовали подобие прямой линии, вот так (сделаем ячейки примерно квадратной формы, для красоты):

 

 

Для этого существует старинный известный алгоритм Алгоритм Брезенхэма. Это один из старейших алгоритмов в машинной графике — он был разработан Джеком Элтоном Брезенхэмом в компании IBM в 1962 году. Все довольно просто, начнем с ситуации когда начальная точка прямой выше и левее конечной, в наших координатах табличного документа, и еще ширина по горизонтали больше чем высота линии по вертикали:

 

 

Уравнение прямой:

Y = X0 + K*X, где

K - это коэффициент наклона:

K = (Хкон - Хнач + 1) / (Yкон - Yнач + 1).

То есть, когда мы увеличиваем X на 1, переходим к следующей ячейке, мы увеличиваем Y на K. K < 1 в нашем случае. Как только накопленный шаг по Y превысит 1, мы увеличиваем Y на 1:

Процедура НарисоватьЛинию(Xнач, Yнач, Xкон, Yкон);
	
	// Алгоритм Брезенхэма на 1С
	
	ДельтаX = Xкон - Xнач + 1;
	ДельтаY = Yкон - Yнач + 1;
	
	КоэфНаклона = ДельтаY / ДельтаX;
	
	ШагПоX = 1;
	ТекущийШагПоY = 0;
	
	Yтек = Yнач;
	Xтек = Xнач;
	
	Пока Xтек <= Xкон Цикл 
		
		Холст.Область(Yтек, Xтек).ЦветФона = ЦветЛинии;
		
		ТекущийШагПоY = ТекущийШагПоY + КоэфНаклона;
		
		Если ТекущийШагПоY >= 1 Тогда
			Yтек = Yтек + 1;
			ТекущийШагПоY = ТекущийШагПоY - 1;
		КонецЕсли;
		
		Xтек = Xтек + 1;
		
	КонецЦикла; 

КонецПроцедуры

Все просто, но это еще не алгоритм Брезенхэма. В то время процессоры производили вычисления с плавающей точкой значительно медленнее, чем целочисленные. На самом деле и сейчас тоже, просто скорость обработки и тех и других выросла на несколько порядков. И чтобы избавиться от медленных вычислений, Брезенхэм придумал уножить все дроби на знаменатель ДельтаX:

Процедура НарисоватьЛинию(Xнач, Yнач, Xкон, Yкон);
	
	// Алгоритм Брезенхэма на 1С
	
	ДельтаX = Xкон - Xнач + 1;
	ДельтаY = Yкон - Yнач + 1;
	
	КоэфНаклона = ДельтаY; // (ДельтаY / ДельтаX) * ДельтаX
	
	ШагПоX = 1;
	ТекущийШагПоY = 0;
	
	Yтек = Yнач;
	Xтек = Xнач;
	
	Пока Xтек <= Xкон Цикл 
		
		Холст.Область(Yтек, Xтек).ЦветФона = ЦветЛинии;
		
		ТекущийШагПоY = ТекущийШагПоY + КоэфНаклона;
		
		Если ТекущийШагПоY >= ДельтаX Тогда // 1 * ДельтаX
			Yтек = Yтек + 1;
			ТекущийШагПоY = ТекущийШагПоY - ДельтаX; // 1 * ДельтаX
		КонецЕсли;
		
		Xтек = Xтек + 1;
		
	КонецЦикла; 

КонецПроцедуры

Получается то же самое, но оптимально по вычислениям.

Теперь надо избавится от начального ограничения, что начальная точка прямой выше и левее конечной и добавить поддержку произвольного начала и конца линии:

Процедура НарисоватьЛинию(Xнач,Yнач,Xкон,Yкон);
	
	// Алгоритм Брезенхэма на 1С
	
	Xt = Xнач;
	Yt = Yнач;
	
	ДельтаX = Xкон - Xнач;
	ДельтаY = Yкон - Yнач;
	
	Если ДельтаY < 0 Тогда
		
		ШагПоY = -1;
		ДельтаY = - ДельтаY;
		
	Иначе
		
		ШагПоY = 1;
	
	КонецЕсли;
	
	Если ДельтаX < 0 Тогда
		
		ШагПоX = -1;
		ДельтаX = - ДельтаX;
		
	Иначе
		
		ШагПоX = 1;
	
	КонецЕсли;
	
	ДельтаY = ДельтаY + 1;
	ДельтаX = ДельтаX + 1;
	
	ТекущийШаг = 0;
	
	Если ДельтаX > ДельтаY Тогда
		
		Пока Xt<>Xкон Цикл
			
			Холст.Область(Yt, Xt).ЦветФона = ЦветЛинии;
			
			Xt = Xt + ШагПоX;
			ТекущийШаг = ТекущийШаг + ДельтаY;
			
			Если ТекущийШаг >= ДельтаX Тогда
				
				Yt = Yt + ШагПоY;
				ТекущийШаг = ТекущийШаг - ДельтаX;
				
			КонецЕсли;
			
		КонецЦикла;

		Холст.Область(Yt, Xt).ЦветФона = ЦветЛинии;
		
	Иначе 
		
		Пока Yt<>Yкон Цикл
			
			Холст.Область(Yt, Xt).ЦветФона = ЦветЛинии;
			
			Yt = Yt + ШагПоY;
			ТекущийШаг = ТекущийШаг + ДельтаX;
			
			Если ТекущийШаг >= ДельтаY Тогда
				
				Xt = Xt + ШагПоX;
				ТекущийШаг = ТекущийШаг - ДельтаY;
				             
			КонецЕсли;
			
		КонецЦикла;

		Холст.Область(Yt, Xt).ЦветФона = ЦветЛинии;
		                                             
	КонецЕсли;
   
КонецПроцедуры

 

Заливка областей

Когда я хаотично линовал экран в ходе тестов, мне прямо захотелось закрасить получившиеяся замкнутые области. Как команда Fill в графических редакторах. На первый взгляд все просто - нам поможет рекурсия:

Процедура ЗакраситьРекурсивно(X, Y, ЦветДоПерекрашивания, НовыйЦветОбласти) 

	Если X > ШиринаПоля ИЛИ Y > ВысотаПоля ИЛИ X < 1 ИЛИ Y < 1 Тогда
		Возврат;
	КонецЕсли;

	Область = Холст.Область(Y, X);
	
	Если Не Область.ЦветФона = ЦветДоПерекрашивания Тогда
		Возврат;
	КонецЕсли;
		
	Область.ЦветФона = НовыйЦветОбласти;

	ЗакраситьРекурсивно(X,   Y-1, ЦветДоПерекрашивания, ЦветЛинии);
	ЗакраситьРекурсивно(X-1, Y, ЦветДоПерекрашивания, ЦветЛинии);
	ЗакраситьРекурсивно(X+1, Y, ЦветДоПерекрашивания, ЦветЛинии);
	ЗакраситьРекурсивно(X,   Y+1, ЦветДоПерекрашивания, ЦветЛинии);
	
КонецПроцедуры

Но не тут-то было. Каждая процедура рекурсивно вызовет саму себя 4 раза. Это очень много - стек очень быстро переполнится на больших областях и программа вылетит с ошибкой. А что самое обидное, эти вызовы по большей части будут ложными, некоторые точки мы будем пытыться раскрасить много раз. Надо как-то сократить количество вызовов и, по возможности, не проверять на перекрашиваемость точки, которые уже были проверены.

Я начал с простого. Можно легко начертить горизонтальную линию от точки клика до пересечения с границей области, например горизонтальная линия на рисунке:

 

 

Процедура ЗакраситьГоризонтальнуюЛиниюНачинаяСТочки(X, Y, ЦветДоПерекрашивания, ЦветПерекрашивания)
	
	Xтек = X;
	Пока Истина Цикл	
		
		Область = Холст.Область(Y, Xтек);
		
		Если Область.ЦветФона <> ЦветДоПерекрашивания Тогда
			Прервать;
		КонецЕсли;
		
		Область.ЦветФона = ЦветПерекрашивания;
		Xтек = Xтек + 1;
		
	КонецЦикла;
	
	Xтек = X - 1;
	Пока Истина Цикл	
		
		Область = Холст.Область(Y, Xтек);
		
		Если Область.ЦветФона <> ЦветДоПерекрашивания Тогда
			Прервать;
		КонецЕсли;
		
		Область.ЦветФона = ЦветПерекрашивания;
		Xтек = Xтек - 1;
		
	КонецЦикла;
	
КонецПроцедуры

Горизонтальную линию нарисовать так же просто, но линию мы рисовать сразу не будем. Соберем координаты точек вертикальной линии от точки клика вверх и вниз до пересечения с границей и поместим их в массив:

 

 

&НаКлиенте
Функция СтруктураТочки(X, Y)

	Рез = Новый Структура;
	Рез.Вставить("X", X);
	Рез.Вставить("Y", Y);
	
	Возврат Рез;

КонецФункции

&НаКлиенте
Процедура ЗафиксироватьВертикальнуюЛиниюНачинаяСТочки(X, Y, ЦветДоПерекрашивания, ЦветПерекрашивания)
	
	Yтек = Y;
	Пока Истина Цикл	
		
		Область = Холст.Область(Yтек, X);
		
		Если Область.ЦветФона <> ЦветДоПерекрашивания Тогда
			Прервать;
		КонецЕсли;
		
		МассивКлючевыхТочек.Добавить(СтруктураТочки(X, Yтек));
		Yтек = Yтек + 1;
		
	КонецЦикла;
	
	Yтек = Y - 1;
	Пока Истина Цикл	
		
		Область = Холст.Область(Yтек, X);
		
		Если Область.ЦветФона <> ЦветДоПерекрашивания Тогда
			Прервать;
		КонецЕсли;
		
		МассивКлючевыхТочек.Добавить(СтруктураТочки(X, Yтек));
		Yтек = Yтек - 1;
		
	КонецЦикла;
	
КонецПроцедуры

А дальше для каждой ключевой точки нарисуем горизонталь:

&НаКлиенте
Процедура ЗакраситьОбластьНачинаяСТочки(X, Y, ЦветДоПерекрашивания, ЦветПерекрашивания)
	
	МассивКлючевыхТочек = Новый Массив;
	
	ЗафиксироватьВертикальнуюЛиниюНачинаяСТочки(X, Y, ЦветДоПерекрашивания, ЦветПерекрашивания, МассивКлючевыхТочек);
	
	Для каждого КлючеваяТочка Из МассивКлючевыхТочек Цикл
	
		ЗакраситьГоризонтальнуюЛиниюНачинаяСТочки(КлючеваяТочка.X, КлючеваяТочка.Y, ЦветДоПерекрашивания, ЦветПерекрашивания);
	
	КонецЦикла;

КонецПроцедуры

Уже начинает получаться:

 

 

Но закрашивает не все, что нужно.

Дальнейшее развитие - в момент, когда мы рисуем очередную горизонталь, проверяем, не проходит ли она вплотную к граничному элементу. Вот например, на рисунке, мы рисуем линию вправо от очередной узловой (ключевой) точки (синяя стрелка) и видим, что сверху к ней вплотную примыкает граница (красная стрелка):

 

 

И если она проходит рядом с границей, то вот эту новую точку, выше нашей линии (ярко-голубая точка и стрелка на рисунке) добавляем в массив ключевых точек.

Так же поступаем если граница проходит ниже рисуемой области и в тех случаях когда линию мы рисуем влево. Итого четыре случая получается.

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

Как это сделать - предлагаю подумать самостоятельно, чтобы потренировать мозги ))
Либо подсмотреть в бесплатной обработке в статье Рисование линий и закрашивание областей в табличном документе 1С

Проверено на следующих конфигурациях и релизах:

  • Бухгалтерия предприятия, редакция 3.0, релизы 3.0.171.23

Математика и алгоритмы Работа с интерфейсом Программист Платформа 1С v8.3

См. также

Работа с интерфейсом Программист Платформа 1С v8.3 1C:Бухгалтерия 1С:ERP Управление предприятием 2 Платные (руб)

Обработка предназначена для создания и управления дашбордами.

2400 руб.

29.06.2020    20216    29    6    

45

Работа с интерфейсом Системный администратор Программист Платформа 1С v8.3 Управляемые формы 1C:Бухгалтерия Платные (руб)

Механизм «Динамическое управление доступом к элементам форм объектов 1С8» предназначен для обеспечения возможности оперативного управления видимостью и доступностью элементов форм документов и справочников продуктов фирмы «1С» «1С:Предприятие 8». Решение универсальное, встраивается в любую конфигурацию с минимальными доработками, что позволяет без проблем обновлять типовые решения.

5000 руб.

14.01.2016    55899    17    23    

43

Работа с интерфейсом Рабочее место Платформа 1С v8.3 Управляемые формы 1C:Бухгалтерия Платные (руб)

Универсальный редактор картинок 1С предназначен для обработки изображений в режиме «Предприятие», с возможностью рисовать на них. Поддерживается работа как в обычных формах (толстый клиент) так и на управляемых формах (тонкий клиент). Обработка позволяет редактировать как картинки, хранимые в базе, так и графические файлы с диска на файловой системе. Помимо базовых функций (изменение размеров, преобразование формата, обрезание картинки, повороты и т.п.) – редактор имеет богатый набор инструментов для рисования. Доступна функция вставки изображения из буфера обмена. Объект может быть использован: на стороне клиента, на стороне сервера, из внешнего соединения. Обработка будет особенно полезна тем, кто вносит картинки в базу (изображения номенклатуры, фотографии физических лиц и т.п.). Функционал реализуется с использованием JavaScript и бесплатного ПО ImageMagick (без использования внешних компонент).

6000 руб.

16.01.2015    64256    45    60    

83

Математика и алгоритмы Работа с интерфейсом Программист Платформа 1С v8.3 Бесплатно (free)

Графические алгоритмы рисования линий и закрашивания областей в 1С. Для одной задачи мне понадобилось соединить точки прямой линией, проблема в том, что эта линия не всегда была горизонтальной. Есть такой алгоритм Брезенхема - один из старейших алгоритмов в машинной графике. Он довольно простой, но интересный. Интересное в нем - это то, как он избавляется от операций с плавающей точкой и переходит от них к полностью целочисленным. Я его использовал, но мои линии почему-то получались какими-то кривыми. Изгибались как-то ближе к концу линии. Я решил создать отдельную обработку и интерактивно все это отладить и разобраться.

10.03.2025    389    17    randomus    4    

8

Работа с интерфейсом Программист Платформа 1С v8.3 1C:Бухгалтерия Абонемент ($m)

"MVC плохо применима в 1С" - познакомьтесь с моделью состояния и, возможно, ваше мнение поменяется! Представленное решение является эволюционным развитием идеи реализации MVC для 1С. В новой версии добавлены DSL для описания модели состояния, а также параметризация свойств параметров и элементов формы.

1 стартмани

05.07.2022    8713    kalyaka    6    

34

WEB-интеграция Работа с интерфейсом Пользователь Платформа 1С v8.3 1С:Розница 2 Платные (руб)

Связка из веб-приложения и расширения для конфигурации 1С:Розница 2.3.

3600 руб.

29.04.2022    14541    2    10    

13

Работа с интерфейсом Платформа 1С v8.3 Платные (руб)

Подсистема условного оформления элементов форм (далее подсистема) предназначена для настройки оформления элементов форм (видимость, доступность, цвет фона, цвет текста и прочее) в пользовательском режиме 1С. Также подсистему возможно использовать для ограничения доступа к реквизитам формы для определенных пользователей (или групп пользователей).

6000 руб.

18.01.2022    10406    1    2    

6

Работа с интерфейсом Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Реализовал простой способ программного создания новых элементов, команд и реквизитов на форме.

25.11.2021    11855    AtamanovYS    19    

152
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. starik-2005 3166 18.03.25 11:56 Сейчас в теме
Детство прям вспомнил, когда на асме это все рисовал на УКНЦ. Блин, тридцать лет уже прошло с тех пор...
2. randomus 300 18.03.25 11:59 Сейчас в теме
(1) Да, я в детстве это делал на Бейсике на компьютере АГАТ. Но с алгоритмом заливки я тогда не справился ))
3. starik-2005 3166 18.03.25 13:12 Сейчас в теме
(2) Мы с другом придумали алгоритм, который как раз точки пересечения помещал в стек и продолжал, пока в стеке не оказывался ноль. Помню, что было просто. Потом круг на амсе рисовал, приведя к целочисленному алгоритму - восемь точек вычислялись за раз, функция корня из (R2 - X2). Я как раз "придумал" функцию следующего квадрата классе в восьмом, просто применял ее в обратную сторону - предыдущий квадрат. На тогдашнем асме только разделить было - никаких корней и синусов с косинусами. Электроника МС-0511 - УКНЦ. Хороший был комп, двухпроцессорный.

ЗЫ: подтыкал тут дисплей на eInk к ардуине какой-то - там как раз драйвер был с целочисленными алгоритмами для рисования линии, круга, заливки, текста. Код очень лаконично прописан на C.
6. randomus 300 18.03.25 14:10 Сейчас в теме
(4)
(3) https://ru.wikipedia.org/wiki/Алгоритм_Брезенхэма - здесь круг тоже есть. Только я не понял, причем тут корень. Суть-то этого Брезенхэма как раз в избавлении от корня, чисто на умножение переход
8. starik-2005 3166 18.03.25 15:38 Сейчас в теме
(6)
причем тут корень
Фактически это приведение y = √ R² - x² к целочисленному варианту.
4. starik-2005 3166 18.03.25 13:37 Сейчас в теме
5. SlavaKron 18.03.25 13:41 Сейчас в теме
Закрашивание растра не требует рекурсии – там линейного цикла достаточно.
7. randomus 300 18.03.25 14:13 Сейчас в теме
(5) об чем, собстно, и речь
Оставьте свое сообщение