MapBasic - Нарисовать сектор на карте. Как?

MapInfo, MapBasic
tems-ya
Интересующийся
Сообщения: 39
Зарегистрирован: 28 янв 2015, 22:07
Репутация: 1
Откуда: Воронеж

MapBasic - Нарисовать сектор на карте. Как?

Сообщение tems-ya » 11 мар 2015, 09:31

Добрый день, коллеги!

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

Могу нарисовать линию по азимуту заданной длины, ну иди точку на окружности. Непонятно что делать с дугой.

1. вроде бы есть стандартный оператор Create Arc, но что-то не попадалось мне примеров его использования и пока не понятно можно-ли им будет воспользоваться, а также нет соответствующей ему функции.

2. существует тупой и дуболомный способ - на дуге нанести N точек и соединить линиями точки по периметру - навскидку метод явно не экономичный и по вычислениям и по размерам объекта, также непонятно сколько точек на xx градусов нужно для гладкого отображения дуги. Если число точек переменное, непонятно как реализовать структуру переменной длины для хранения переменного числа точек.

Буду благодарен если кто-то сможет что-либо подсказать по данному вопросу или поделится кусками кода.

Спасибо.

thegeo
Активный участник
Сообщения: 160
Зарегистрирован: 17 янв 2012, 18:51
Репутация: 74

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение thegeo » 11 мар 2015, 23:03

Оператор построения дуги имеет следующий вид
Create Arc Into Window idMap (x1,y1) (x2,y2) _start _end
Все обозначения в соответствии с рисунком.
Прилагаемый код строит сектор, все необходимые комментарии в коде.
Строится точка {x0,y0} и дуга, далее к этим объектам применяется оператор ConvexHull (возвращает выпуклую оболочку для объектов аргументов) что приводит к некоторому загрублению результата. Если требуется большая точность, то нужно непосредственно вычислить координаты точек на дуге в направлении End и Start и этих данных будет достаточно для определения искомого объекта.
Вложения
sector.zip
(877 байт) 397 скачиваний
miHG127.png
miHG127.png (4.16 КБ) 14658 просмотров

tems-ya
Интересующийся
Сообщения: 39
Зарегистрирован: 28 янв 2015, 22:07
Репутация: 1
Откуда: Воронеж

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение tems-ya » 12 мар 2015, 13:32

Sector_rezult.png
Sector_rezult.png (4.81 КБ) 14622 просмотра
Большое спасибо за пример. Пытаюсь разобраться. Пока получается не совсем то что хотелось. Дуга почему-то не круглая :(
Вложения
Sector_rezult1.png
Sector_rezult1.png (5.76 КБ) 14622 просмотра

thegeo
Активный участник
Сообщения: 160
Зарегистрирован: 17 янв 2012, 18:51
Репутация: 74

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение thegeo » 12 мар 2015, 14:25

Изображение дуги в любом случае дискретно. Качество приближения к круговой кривой определяется оператором Set Resolution N. Кроме того нужно учитывать возможность используемой координатной системы отображать заявленную дискретность.
Вложения
miHG134.png
miHG134.png (56.02 КБ) 14612 просмотров

tems-ya
Интересующийся
Сообщения: 39
Зарегистрирован: 28 янв 2015, 22:07
Репутация: 1
Откуда: Воронеж

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение tems-ya » 12 мар 2015, 17:43

Попробовал все пересчитать по формулам

RZ = 6371000 'Радиус Земли в м

lat1_1 = y0 + 300*cos(Azimut*PI/180)/(RZ*PI/180)
lon1_1 = x0 + 300*sin(Azimut*PI/180)/cos(y0*PI/180)/(RZ*PI/180)

Стало лучше. Но все равно итоговый результат не устраивает. Видно заметное расхождение от прорисованных отрезков в заданном направлении. Непонятно, в чем причина. Такое ощущение, что приведенные выше формулы не точны. Можно-ли как-то победить наблюдаемое расхождение?
Вложения
Sector_rezult3.png
Sector_rezult3.png (7.95 КБ) 14586 просмотров


thegeo
Активный участник
Сообщения: 160
Зарегистрирован: 17 янв 2012, 18:51
Репутация: 74

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение thegeo » 12 мар 2015, 21:57

Замените код определения координат углов покрытия (x1,y1,x2,y2). Чтобы не переходить к громоздким вычислениям на сфере, определил их косвенно исходя из возможностей МВ.

dim cir as object
R=1000 'в метрах
cir=CreateCircle(x0,y0,R)
x1=ObjectGeography(cir,OBJ_GEO_MINX)
y2=ObjectGeography(cir,OBJ_GEO_MINY)
x2=ObjectGeography(cir,OBJ_GEO_MAXX)
y1=ObjectGeography(cir,OBJ_GEO_MAXY)


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

tems-ya
Интересующийся
Сообщения: 39
Зарегистрирован: 28 янв 2015, 22:07
Репутация: 1
Откуда: Воронеж

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение tems-ya » 15 мар 2015, 15:52

Попробовал все-таки додавить идею с громоздкими вычислениями на сфере (т.к. вопрос важный сам по себе). В результате получилось как-то:

Код: Выделить всё

define PI 3.1415926535897932384626433832795
define SQRT2 1.4142135623730950488016887242097
'Средний радиус Земли в м
define RZ 6371000

sub DrowSector_menu_func

  Dim azimut, SectorWidth, r , LAT0, LON0 as float
  
	'	Данные для примера
    azimut = 120         'направление центра сектора в градусах
	SectorWidth = 60   'ширина сектора в градусах
	r = 300            'длина сектора на местности в метрах
	LON0 = 35.976
	LAT0 = 56.514
	
	'Call DrowSector(0, 60, 300 ,56.514,35.976)
	Call DrowSector(azimut, SectorWidth, r , LAT0, LON0)
	
End Sub


sub DrowSector( ByVal azimut as float, ByVal SectorWidth as float, ByVal r as float, ByVal LAT0 as float, ByVal LON0 as float  ) 
	
'	система координат устанавливается по таблице 
'	в которой выполняется построение (WGS84)
	'Set CoordSys table input_table   
	Set Distance Units "m"
	Set Resolution 1.8*SectorWidth 'определяет точность отрисовки дуги, чем больше тем выше точность
	
'	Для использования Create Arc потребуются дополнительные вычисления. Нужно определить
'   координаты концов одной диагонали квадрата, в который может быть вписана воображаемая 
'   окружность того же радиуса, что и у наша дуги
	dim ArcLat1, ArcLon1 as float  'координаты левого верхнего угла квадрата  (azimut = 315)
	dim ArcLon2, ArcLat2 as float  'координаты правого нижненго угла квадрата (azimut = 135)

'   и вычислить начальный и конечный угол дуги относительно 0° (направление на восток),
'   отсчитываемые против часовой стрелки 	
	dim ArcAngleStart, ArcAngleEnd as float  'углы начала и конца дуги отсчитанные от востока

    'Вычисляем координаты диагонали 	
    Call calc_coordinats(ArcLat1, ArcLon1, r*SQRT2, 315, LAT0, LON0)
    Call calc_coordinats(ArcLat2, ArcLon2, r*SQRT2, 135, LAT0, LON0)
    
    'Вычисляем углы
    ArcAngleStart = Arc_angle_convert(azimut + SectorWidth/2)
    ArcAngleEnd   = Arc_angle_convert(azimut - SectorWidth/2)

'   -------------------------------------------------
	dim idMap,n as integer
	idMap = frontWindow()

	dim curArc as object 
    dim x1,y1, x2,y2 as float

	
'	выполняем построение на редактируемом слое (ss)
	Create Point Into Window idMap (LON0,LAT0)
    'рисуем дугу
	Create Arc Into Window idMap (ArcLon2,ArcLat2) (ArcLon1,ArcLat1) ArcAngleStart ArcAngleEnd
    
    'число строк в открытой таблице
	n = TableInfo(input_table,TAB_INFO_NROWS)
    'выбираем последние добавленные записи Point и Arc
	Select * From input_table Where rowid > n-2
	Run Menu Command M_OBJECTS_CONVEX_HULL

'   -------------------------------------------------
'   руками рисуем линии левой и правой границ сектора

	dim latP1,lonP1, azimut_left   as float
	dim latP2,lonP2, azimut_rigth  as float
	
    azimut_left = calc_Azimut_left(azimut, SectorWidth)
    Call calc_coordinats(latP1, lonP1, r, azimut_left, LAT0, LON0)

    azimut_rigth = calc_Azimut_rigth(azimut, SectorWidth)
    Call calc_coordinats(latP2, lonP2, r, azimut_rigth, LAT0, LON0)

	Create Line Into Window idMap (LON0,LAT0) (lonP1,latP1)
	Create Line Into Window idMap (LON0,LAT0) (lonP2,latP2)
	
End Sub

'--------------------------------------------------------------------------------------
'      Пересчет азимутов для оператора Create Arc 
'--------------------------------------------------------------------------------------
Function Arc_angle_convert(ByVAL azimut as float) as float

    dim az as float

az = 90 - azimut

If az < 0 Then 
  Arc_angle_convert = 360 + az
Else
  Arc_angle_convert = az
End If

End Function


'--------------------------------------------------------------------------------------
'  Вычисление координаты точки расположенной на расстоянии r в направлении azimut
'--------------------------------------------------------------------------------------
Sub calc_coordinats(lat as float, lon as float, ByVal r as float, ByVal azimut as float, ByVal lat0 as float, ByVal lon0 as float )

	'dim PI,RZ  as float
    'PI    = 3.1415926535897932384626433832795
    'RZ    = 6371000                             'Средний радиус Земли в м

  lat = lat0 + r*cos(azimut*PI/180)/(RZ*PI/180)
  lon = lon0 + r*sin(azimut*PI/180)/cos(lat0*PI/180)/(RZ*PI/180)
  
End Sub


'--------------------------------------------------------------------------------------
'           Вычисление азимута левой границы сектора 
'--------------------------------------------------------------------------------------
Function calc_Azimut_left(Azimut as float, SectorWidth as float) as float

  Dim SectorWidth_div2 as Float

SectorWidth_div2 = SectorWidth/2
If (Azimut - SectorWidth_div2) < 0 Then
	calc_Azimut_left = 360 - (SectorWidth_div2 - Azimut )
Else
	calc_Azimut_left = Azimut - SectorWidth_div2
End If

End Function

'--------------------------------------------------------------------------------------
'           Вычисление азимута правой границы сектора 
'--------------------------------------------------------------------------------------
Function calc_Azimut_rigth(Azimut as float, SectorWidth as float) as float

  Dim SectorWidth_div2 as Float

SectorWidth_div2 = SectorWidth/2
If (Azimut + SectorWidth_div2) > 360 Then
	calc_Azimut_rigth = SectorWidth_div2 - (360 - Azimut )
Else
	calc_Azimut_rigth = Azimut + SectorWidth_div2
End If

End Function


Осталось нерешенным несколько проблем:
1)

Код: Выделить всё

 Run Menu Command M_OBJECTS_CONVEX_HULL 
вызывает меню где требуется ручное вмешательство. Если нужно нарисовать 1000 секторов - это становиться неприемлемым. Можно-ли это как-то побороть или обойти?

2) После создания сектора остается дуга. По идеи ее необходимо удалить. Вопрос как?

3)Руками нарисованные линии-границы секторов немного, но не совпадают с дугой... В рамках данного подхода, если отталкиваться от необходимости руками замкнуть контур, требуется как-то их свести друг с другом. Непонятно как... (Повысить точность вычислений на сфере?? Воспользоваться какими-нибудь процедурами проверки??) Лучше бы данной процедуры избежать совсем...

В свете вышеизложенного гораздо более перспективным выглядит предложенный выше подход:
1. Построить круг
2. Средствами MapBasic получить координаты минимального описывающего прямоугольника
3. По этим координатам построить дугу
4. Превратить дугу в полилинию
5. Средствами MapBasic получить координаты концов дуги (точные!!!)
... далее пока не понятно...
6. Нарисовать две линии из центра ТОЧНО в концы дуги
7. Замкнуть контур и превратить его в область
...или
6. Добавить к полилинии дуги еще одну точку ЦЕНТР и как-то суметь превратить все это сектор???

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

Sibit
Активный участник
Сообщения: 216
Зарегистрирован: 21 окт 2009, 13:29
Репутация: 28
Откуда: Новосибирск

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение Sibit » 16 мар 2015, 05:52

tems-ya писал(а): 6. Добавить к полилинии дуги еще одну точку ЦЕНТР и как-то суметь превратить все это сектор???
Я думаю, проще создать дугу, превратить ее в полилинию и добавить в нее отрезки до центра. После этого можете спокойно превращать все в полигон.
tems-ya писал(а): В общем пока вопросов больше чем ответов. Актуален вопрос с быстродействием. Непонятно, что, где и когда быстрее работает? Оператор, функция?
А в чем собственно проблема? Сколько у вас вычислений? Я считаю, пока не решите задачу и не проверите на реальных данных, думать о быстродействии рано.

Ну и еще вопрос: какая точность отрисовки сектора вам необходима?

thegeo
Активный участник
Сообщения: 160
Зарегистрирован: 17 янв 2012, 18:51
Репутация: 74

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение thegeo » 16 мар 2015, 14:48

Реализация изложенного выше подхода. И к вопросу о точности результата.
Вложения
sector2.zip
(2.37 КБ) 385 скачиваний
miHG141.png
miHG141.png (94.3 КБ) 14401 просмотр

thegeo
Активный участник
Сообщения: 160
Зарегистрирован: 17 янв 2012, 18:51
Репутация: 74

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение thegeo » 16 мар 2015, 14:55

По построению без диалога:
1. функция ConvexHull();
2. оператор Create Object As ConvexHull

tems-ya
Интересующийся
Сообщения: 39
Зарегистрирован: 28 янв 2015, 22:07
Репутация: 1
Откуда: Воронеж

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение tems-ya » 17 мар 2015, 20:41

По поводу точности - чтобы глаз не резало при приближении.

При попытки вызвать

Код: Выделить всё

Sector = ConvexHull(selection.obj)
где в selection объект дуга и точка центра выдает ошибку:

Для операции оконтуривания требуется минимум 3 узла на входе. Так что красивая идея нарисовать дугу, поставить точку в центре нежизнеспособна. Пока удалось построить сектор, только честно превратив дугу в полилинию, определив координаты концов, нарисовав в них линии, объединив и преобразовав контур объект.

Как объект уже сформированный (сектор) вставить на активную карту?

Код: Выделить всё

    dim  Sector as object 
    Sector = CreateSector(....)
    ....
      ? Показать на текущей карте ? 

thegeo
Активный участник
Сообщения: 160
Зарегистрирован: 17 янв 2012, 18:51
Репутация: 74

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение thegeo » 18 мар 2015, 00:23

Объедините точку и дугу в один объект (Objects Combine…) и далее
Insert Into таблица ( obj ) Values (ConvexHull(объединенный объект))

Sibit
Активный участник
Сообщения: 216
Зарегистрирован: 21 окт 2009, 13:29
Репутация: 28
Откуда: Новосибирск

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение Sibit » 18 мар 2015, 08:00

tems-ya писал(а):По поводу точности - чтобы глаз не резало при приближении.
При каком приближении? В MapInfo всегда будет существовать приближение, при котором точки дуги и точки приближающей полилинии будут расходиться.
tems-ya писал(а): При попытки вызвать

Код: Выделить всё

Sector = ConvexHull(selection.obj)
где в selection объект дуга и точка центра выдает ошибку:
Вообще-то, Selection.Obj - это объект, а не группа объектов. Так что ругается правильно. Точку оконтурить нельзя.
tems-ya писал(а):Так что красивая идея нарисовать дугу, поставить точку в центре нежизнеспособна.
С чего это? Отличная идея, все работает в два действия.
tems-ya писал(а):Пока удалось построить сектор, только честно превратив дугу в полилинию, определив координаты концов, нарисовав в них линии, объединив и преобразовав контур объект.
Зачем определять координаты? просто добавляете узел и все.
tems-ya писал(а): Как объект уже сформированный (сектор) вставить на активную карту?
Объект вставляется не в карту а в таблицу. Если хотите, что бы он был только в окне, тогда вставляйте в косметический слой окна карты(детали в документации), но принцип там тот же.

Аватара пользователя
Игорь Белов
Гуру
Сообщения: 2229
Зарегистрирован: 04 янв 2011, 22:00
Репутация: 1501
Откуда: Казань

Re: MapBasic - Нарисовать сектор на карте. Как?

Сообщение Игорь Белов » 18 мар 2015, 18:16

tems-ya писал(а):По поводу точности - чтобы глаз не резало при приближении.
Sibit писал(а):При каком приближении? В MapInfo всегда будет существовать приближение, при котором точки дуги и точки приближающей полилинии будут расходиться.
Мне одному послышалось «квадратура круга»? :twisted:
The purpose of computing is insight, not numbers

Ответить

Вернуться в «MapInfo»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 11 гостей