Как плавно менять координаты точки на карте?

0 голосов
спросил 07 Июнь, 10 от DevProSoftware (1,040 баллов) в категории Программные продукты Esri
Господа, наставьте, пожалуйста на путь истинный.
Нарисовал точку в точечном слое карты:

  pLayer := MapControl.Layer[0];

  pFeatLayer := pLayer as IFeatureLayer;
  pFeatClass := pFeatLayer.FeatureClass;

  pPoint := CoPoint.Create as IPoint;
  pPoint.X := 20;
  pPoint.Y := 20;

  pGeometry := pPoint as IGeometry;
  pFeature := pFeatClass.CreateFeature;

  pFeature.Shape := pGeometry;

  pFeature.Value[pFeatClass.FindField('Name')] := 'Точка';
  pFeature.Value[pFeatClass.FindField('POPULATION')] := '100';
  pFeature.Value[pFeatClass.FindField('CONTINENT')] := 'Asia';

  pFeature.Store;

  MapControl.ActiveView.PartialRefresh(esriViewGeography,nil,nil);

Мне нужно динамически менять координаты точки. Я делаю это в событиях компонентов TSpinEdit:
procedure TForm.SpinEditXChange(Sender: TObject);
begin
  pPoint.X := SpinEditX.Value;
  pFeature.Store;
  MapControl.ActiveView.PartialRefresh(esriViewGeography,nil,nil);
end;
procedure TForm.SpinEditYChange(Sender: TObject);
begin
  pPoint.Y := SpinEditY.Value;
  pFeature.Store;
  MapControl.ActiveView.PartialRefresh(esriViewGeography,nil,nil);
end;
Точка меняет свои координаты нормально, но при вызове PartialRefresh перерисовывается вся карта, что очень некрасиво, а если не вызывать PartialRefresh, то точка на карте не перерисовывается.
Как можно плавно перерисовывать точку?

29 Ответы

0 голосов
ответил 08 Июнь, 10 от DevProSoftware (1,040 баллов)
Благодарю, но я уже смотрел по этим и аналогичным ссылкам и не нашёл подходящих примеров
0 голосов
ответил 08 Июнь, 10 от pooperec (10,820 баллов)
Да? А... Я понял, Вам пример на Делфи. Такого - увы нету, переучивайтесь на C# .NET.

Или прочитайте сл. абзац:
"Outbound Interfaces (Event Handling)
     Outbound interfaces are used when ArcGIS sends a message to lots of objects that have a listening ear. These messages are also known as events. For instance, when the Selection object in ArcCatalog has changed, it fires an OnSelectionChanged event to all objects which implement the IGxSelectionEvents interface and have “registered” to listen to that event.
     In the Visual Basic examples, you’ll see code like this:

     Private WithEvents pGxSelection as GxSelection

     In Delphi, it’s not as simple. First, your object declaration must specify that it’s implementing a specific outbound interface. If your object is already created and coded up, then use the Type Library editor, as described on page 13, to add an interface like IGxSelectionEvents to your Implemented Interfaces list. Then refresh the implementation so Delphi creates function stubs for you.
     Second, you have to declare two (preferably private) variables: one of type IInterface and one of type LongInt. The IInterface variable will always be pointing to the ArcGIS object that your object is listening to. The LongInt is a sort of handle representing your listening connection to ArcGIS.
     Third, in an “appropriate” method of your object, you must declare that you are an object listening to an ArcGIS object. By “appropriate” method, I mean one that’s going to be called once by ArcGIS, such as OnCreate or Activate. (See “Overriding the Create Constructor”, above, for more ideas). Assign the IInterface variable to an object in ArcGIS that’s going to be sending you events. Continuing with the IGxSelectionEvents example, you’ll need to listen to the GxSelection object. Obtain a reference to the object through IGxCatalog.Selection and you’ll get an IGxSelection pointer. Cast it to an IInterface pointer and store it to the IInterface variable you created.
     To declare that you are a listener, call the InterfaceConnect method (declared in the ComObj unit). The first parameter to this function is the IInterface variable. The second parameter is the name of the Interface that you are listening to, such as ISelectionEvents. The third parameter is “Self as IInterface” (meaning that this object, Self, is to be counted as listening), and the fourth parameter is the LongInt variable.
     Fourth, in an “appropriate” method of your object, you must stop listening for the event. By “appropriate” method, I mean one that destroys your object, or tells your object it’s going to be destroyed. You then call InterfaceDisconnect. The first parameter to this method is the IInterface variable as before. The second parameter is the name of the interface you were listening to, like IGxSelectionEvents. The third parameter is the LongInt variable.
"

А потом прочтите мой предидущий пост - Вам нужно сделать тоже, только с диспинтерфейсом IActiveViewEvents.
0 голосов
ответил 09 Июнь, 10 от DevProSoftware (1,040 баллов)
Насколько я правильно понял по переводу и додумал, нужно сделать где-то так:
...
var
  pActiveViewEvents : iActiveViewEvents;
  long : longint;
begin
  InterfaceConnect(pActiveViewEvents, iActiveViewEvents, self as iActiveViewEvents, long);
end;
Только к сожалению не понимаю, что дальше с этим делать...
0 голосов
ответил 09 Июнь, 10 от pooperec (10,820 баллов)
1. First, your object declaration must specify that it’s implementing a specific outbound interface.

TMyForm = class (TForm, IActiveViewEvents)
   //компоненты
protected
    // что-то
    // методы IActiveViewEvents
private
    pAVCallBack : IInterface;
    pAVHWN      : integer;
    // что-то ещё
end;

implementation

TMyForm.OnCreate (Sender : TObject);
Begin
pAVCallBack := pActiveView as IActiveViewEvents;
InterfaceConnect(pAVCallBack, iActiveViewEvents, self as iActiveViewEvents, pAVHWN);
End;
    
0 голосов
ответил 10 Июнь, 10 от DevProSoftware (1,040 баллов)
Спасибо за столь детальное описание.
Сделал всё следуя Вашим рекомендациям. У меня получилось следующее.
Событие AfterItemDraw вызывается почему-то по 3 раза для каждого слоя при загрузке программы. В этом событии пишу:
procedure TForm1.AfterItemDraw(Index: Smallint; const Display: IDisplay; phase: esriDrawPhase);
begin
    Display.DrawPoint(pGeometry);
end;
где pGeometry - ранее созданная точка в событии TForm1.OnCreate.
Точка при вызове события не рисуется.
В программе динамически меняю координаты точки, но событие AfterItemDraw больше не вызывается. Вы писали выше, что рисовать в этом событии на этапе отрисовки переднего плана, но я не совсем въезжаю, как это, наверно в этом загвоздка? Или что я не так делаю?

0 голосов
ответил 10 Июнь, 10 от pooperec (10,820 баллов)
DevProSoftware
Дальше читайте мануал.
Я так понимаю Вы систему трекинга для кого-то пишете?
Поймите, я проживаю в Украине, и обучать конкурента это уже как бы "не кошерно"...

Спасибо за понимание.
0 голосов
ответил 10 Июнь, 10 от DevProSoftware (1,040 баллов)
Мне всё это нужно для написания диссертации. Может быть поможете всё же по поводу этой точки, дальше я постараюсь сам уже. Спасибо.
0 голосов
ответил 10 Июнь, 10 от pooperec (10,820 баллов)
*Мысли вслух (нытье)*
Как тяжело в этой стране...
А у меня вот на кандидатскую времени не остается.

И денег нету.
Никто не хочет платить.

Всем кажется что специалист который на себе тянет добрую половину работы не должен получать добрую половину денег.... Даже 10 части не должен получать...

Люди считают что добрых 3 дня моей работы стоит около 500 рублей (российских)... А наши вообще так не считаю... Как я устал.

*Закончил ныть*

У Вас есть два события OnItemDraw (происходит для каждого слоя, три раза (отрисовка геометрии, отрисовка выборки, отрисовка аннотации(подписей)).

В Вашем случаем нужно использовать метод AfterDraw.
Дальше примерно такой код:

procedure TТруляля.AfterDraw(const Display: IDisplay;
phase: esriViewDrawPhase);
var
i:integer;
begin
if phase<>32 then exit; //нам нужно только отрисовка "передника"
try
if (ppoint<>nil) then Begin
    if pMarkerSymbol<>nil then Display.SetSymbol(pMarkerSymbol as ISymbol);
    Display.Drawpoint(pPoint);
End;
except on E: Exception do Begin
   {$I-}
      ShowMessage(E_PREF+'{569FBF7F-A686-491B-A4F6-A4F86CCFE807} '+E.Message);
   {$I+}
End;
end;

end;

Игого:
pMarkerSymbol - IMarkerSymbol (символ отрисовки)
ppoint        - IPoint (Ваша точка)

Теперь генерация события. Как только Ваш объект переместился, вам нужно (по таймеру, событию, или ещё по чему-то) сделать следующее:
1. Поменять координаты точки.
2. Вызвать pActiveView.PartialRefresh (32{и это важно},pPoint,nil)

0 голосов
ответил 10 Июнь, 10 от DevProSoftware (1,040 баллов)
Мерси. Но программа вылетает на строке Display.Drawpoint(pPoint);
Правда я не инициализировал pMarkerSymbol - не могу найти класс, с помощью которого это делается. И зачем этот pMarkerSymbol вообще нужен?
0 голосов
ответил 10 Июнь, 10 от pooperec (10,820 баллов)
0. pPoint не нил? А.... Проинициализируйте Маркер..
1. CoSimpleMarkerSymbol например
2. Методі посмотрите - поймёте (устанавливать размер, цвет и прочее).
Добро пожаловать на сайт Вопросов и Ответов, где вы можете задавать вопросы по GIS тематике и получать ответы от других членов сообщества.
...