Страница 1 из 1

Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 26 мар 2010, 18:54
Оборотень
В общем, при обработке рукописных и прочих данных часто встречается такая формулировка: "точка (место сбора, отлова, встречи и пр.) расположена в N км к востоку (любое направление) от г. (пос., с. и прочие реперы) Такого-то". Иными словами - даны репер, азимут и расстояние.
Требуется определить координаты (в любой проекции, но как правило, требуются угловые) этого места, имея координаты точки отсчёта (репера).
Как проще всего сделать это в ГИС? Использую ArcGIS 9.3 (лицензия ArcINFO).
Исходные данные - любые - шейпы, Feature Class типа Point.
Результат также возможен в любом виде - хоть новый объект класса Point, хоть рассчитанные координаты.
Есть ли готовый инструмент (в указанной ГИС)? Или требуется скрипт по вычислению координат на сфере - что в принципе мог бы сделать и сам, хотя тоже затрудняюсь - куда его писать?
Искал в Сети и на этом сайте, но (здесь) нашёл только задачу на построение по двум азимутам.
Буду благодарен как за прямой совет, так и за ссылку на статью.
Думаю, неплохо было бы создать такую статью (или ссылку) в FAQ сайта.
P.S. Репер - это не по высоте, а по координатам, как правильно обозвать - не знаю :(

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 26 мар 2010, 20:41
KolesovDmitry
Оборотень писал(а):"точка (место сбора, отлова, встречи и пр.) расположена в N км к востоку (любое направление) от г. (пос., с. и прочие реперы) Такого-то". Иными словами - даны репер, азимут и расстояние.
Требуется определить координаты (в любой проекции, но как правило, требуются угловые) этого места, имея координаты точки отсчёта (репера).
...
Результат также возможен в любом виде - хоть новый объект класса Point, хоть рассчитанные координаты.
Задача знакома, часто имел с ней дело (правда, работал только на плоскости). Как в arcGIS с этим делом не знаю, но общая идея проста: берет точки и производите ее трансформацию (возможность векторной трансформации дает многое ПО) по нужным параметрам (домножаете на нужный коэф, прибавляете нужный параметр и т.д.). Конкретная реализация зависит от того, что за возможности предоставляет ваше ПО.

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 27 мар 2010, 02:31
Boris
Эта задача имеет так много толкований. В вашем описании нет никакого азимута, кроме воображаемого. Поскольку не сказано, что принято направлением на север и в какой системе координат. Север может быть - астрономический (направление на Полярную звезду), географический - направление на север на конкретной карте или листе карты, магнитный - вообще нет ни на одной карте, за исключением военных или около военных.

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 31 мар 2010, 18:05
Оборотень
Хорошо, уточню.
1) Точность требуется почти минимальная (т.к. описания всеравно субъективные). Азимут будем считать - по меридиану, т.е. получается угол от географического Севера (правильно?). Причём в описаниях редко встречается угол, отличный от 90° или 45°. От СК, как я понимаю, будет зависеть только способ расчёта - Декартовы координаты (ну с поправкой на геоид) или полярные (тоже с какой-нить там поправкой :) ).
2) Интересует как раз _конкретный_ приём. Для _конкретного_ ПО (желательно - используемый мной, как уже упоминал, ArcGIS). Я конечно, мог бы вспомнить основы геометрии и считать непосредственно координаты в чём-нибудь типа Excel, но это больно уж неэффективно; кроме того, возможно имеется готовый инструмент.

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 31 мар 2010, 18:49
KolesovDmitry
Оборотень писал(а): Интересует как раз _конкретный_ приём. Для _конкретного_ ПО
Могу рассказать, как это можно сделать в GRASS, если конечно, это имеет смысл

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 31 мар 2010, 19:08
SS_Rebelious
KolesovDmitry писал(а):Могу рассказать, как это можно сделать в GRASS, если конечно, это имеет смысл
Да конечно имеет! Особенно если оформить в виде статьи!

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 01 апр 2010, 17:13
Оборотень
KolesovDmitry писал(а): Могу рассказать, как это можно сделать в GRASS, если конечно, это имеет смысл
Да, пожалуста расскажите. Тоже интересно, хотя с этим софтом не довелось иметь дела. Может, по аналогии получится.

Re: Задача: "точка находится в N км СВ от заданной" - как?

Добавлено: 01 апр 2010, 18:13
pooperec
Вот рендерер. Рисует пеленг на заданный азимут для всех точек. Значение береться из Z координаты, для скорости. Отрисовка до 400 000 отметок / сек. Также есть возможность программно задавать символ точки пеленга и линии.

Недостаток - все пеленги рисуються с одной заданной длинной.

Разберётесь?

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

const
 CLASS_PelengRenderer : TGUID = '{52CDBCF0-1514-42E5-8726-EA2206339949}';

type 
  IPelengRenderer = interface(IUnknown)
    ['{D4332118-638C-4CDE-B169-A319B8AE8707}']
    procedure SetDistance(Distance: Integer); safecall;
    function Get_ParentSymbol: IUnknown; safecall;
    procedure Set_ParentSymbol(const Value: IUnknown); safecall;
    function Get_LineSym: IUnknown; safecall;
    procedure Set_LineSym(const Value: IUnknown); safecall;
    function Get_PointSym: IUnknown; safecall;
    procedure Set_PointSym(const Value: IUnknown); safecall;
    property ParentSymbol: IUnknown read Get_ParentSymbol write Set_ParentSymbol;
    property LineSym: IUnknown read Get_LineSym write Set_LineSym;
    property PointSym: IUnknown read Get_PointSym write Set_PointSym;
  end;

type
  TPelengRenderer = class(TTypedComObject, IPelengRenderer, IFeatureRenderer)
  public
   pExSet : IFeatureIDSet;
  Distance : integer;
  pSym  : ISymbol;
  pLineSym : ISymbol;
  pPointSym : iSymbol;
  protected
    function CanRender(const featClass: IFeatureClass;
      const Display: IDisplay): WordBool; safecall;
    function Get_RenderPhase(DrawPhase: esriDrawPhase): WordBool; safecall;
    function Get_SymbolByFeature(const Feature: IFeature): ISymbol; safecall;
    procedure _Set_ExclusionSet(const Param1: IFeatureIDSet); safecall;
    procedure Draw(const cursor: IFeatureCursor; DrawPhase: esriDrawPhase;
      const Display: IDisplay; const TrackCancel: ITrackCancel); safecall;
    procedure PrepareFilter(const fc: IFeatureClass;
      const queryFilter: IQueryFilter); safecall;
    procedure SetDistance(Distance: Integer); safecall;
    function Get_ParentSymbol: IUnknown; safecall;
    procedure Set_ParentSymbol(const Value: IUnknown); safecall;
    function Get_LineSym: IUnknown; safecall;
    procedure Set_LineSym(const Value: IUnknown); safecall;
    function Get_PointSym: IUnknown; safecall;
    procedure Set_PointSym(const Value: IUnknown); safecall;
    {Declare IPelengRednderer methods here}
  end;

implementation

uses ComServ;

function TPelengRenderer.CanRender(const featClass: IFeatureClass;
  const Display: IDisplay): WordBool;
begin
   Result:=false;
  if featClass.ShapeType=esriGeometryPoint then Result:=true;
end;

function TPelengRenderer.Get_RenderPhase(DrawPhase: esriDrawPhase): WordBool;
begin
   if (DrawPhase=esriDPGeography)OR(DrawPhase=esriDPSelection) then Result:=true
  else Result:=false;
end;

function TPelengRenderer.Get_SymbolByFeature(const Feature: IFeature): ISymbol;
begin

end;

procedure TPelengRenderer._Set_ExclusionSet(const Param1: IFeatureIDSet);
begin
  pExSet := Param1;
end;

procedure TPelengRenderer.Draw(const cursor: IFeatureCursor;
  DrawPhase: esriDrawPhase; const Display: IDisplay;
  const TrackCancel: ITrackCancel);
var
bContinue : boolean;
  pRow : IRow;
  o : integer;
  pPointF: IPoint;
  pPointT:IPoint;
  pExclude: Boolean;
  pOID: Integer;
  pLine : IPolyline;
    pF : IFeature;
  Angl : double;
begin
    if (Display=nil)OR(DrawPhase<>esriDPGeography) then exit;
    if (pLineSym=nil) or (pSym=nil) then exit;

    If trackCancel<>nil Then bContinue := trackCancel.Continue;

    pF:=cursor.NextFeature;

//    if pF<>nil then
//     o :=pF.Fields.FindField('AZIMUTH');
//    if o=0 then exit;

     while (pF<>nil) AND (bContinue) do Begin
          pPointT:=nil;
          pPointF:=nil;
          Angl:=0;
          pPointF:=pF.Shape as IPoint;
          Angl := pPointF.Z;
          if (round(Angl) div 360)>0  then Angl:=Angl - 360*(round(Angl) div 360)
          else Angl:=Angl - 360*(Angl);

          pExclude :=false;
          if pExSet<>nil then Begin
            pOID:=pF.OID;
            if pExSet.Contains[pOID] then pExclude:=true;
          End;

       if (pPointF.X>180)or(pPointF.X<-180) then pExclude:=true;
       if (pPointF.Y>90)or(pPointF.Y<-90) then pExclude:=true;

       if not(pExclude) then Begin
         try

         pPointT:=CoPoint.Create as IPoint;

         pPointT.Y:=pPointF.Y+20*cos(double(Angl)*pi/180);
         pPointT.X:=pPointF.X+20*sin(double(Angl)*pi/180);
//
         if (Angl>=0) then
         if NOT((pPointT.X>180)or(pPointT.X<-180)) then
         if NOT((pPointT.Y>90)or(pPointT.Y<-90)) then Begin
           pLine:=CoPolyline.Create as IPolyline;
           pLine.FromPoint:=pPointF;
           pLine.ToPoint:=pPointT;
           Display.SetSymbol(pLineSym);
           Display.DrawPolyline(pLine);
           Display.SetSymbol(pPointSym);
           Display.DrawPoint(pPointF);
         End else pPointT:=nil;
//         Display.SetSymbol(pSym);
//         Display.DrawPoint(ppointF);
         except on E:Exception do
          {$I-}
            ShowMessage(E.Message);
          {$I+}
         end;

       End;
        If trackCancel<>nil Then bContinue := trackCancel.Continue;
        pF:=cursor.NextFeature;

     End;
end;

procedure TPelengRenderer.PrepareFilter(const fc: IFeatureClass;
  const queryFilter: IQueryFilter);
begin
   if pExSet<>nil then
    if pExSet.Count>0 then Begin
      queryFilter.AddField(fc.OIDFieldName);
    End;
end;

procedure TPelengRenderer.SetDistance(Distance: Integer);
begin
  Distance:=Distance;
end;

function TPelengRenderer.Get_ParentSymbol: IUnknown;
begin
 Result:=pSym;
end;

procedure TPelengRenderer.Set_ParentSymbol(const Value: IUnknown);
begin
if supports(Value, ISymbol) then
  pSym:=Value as ISymbol;
end;

function TPelengRenderer.Get_LineSym: IUnknown;
begin
 Result:=pLineSym;
end;

procedure TPelengRenderer.Set_LineSym(const Value: IUnknown);
begin
 if supports(Value,Isymbol) then
   pLineSym:=Value as ISymbol;

end;

function TPelengRenderer.Get_PointSym: IUnknown;
begin
   Result:=pPointSym;
end;

procedure TPelengRenderer.Set_PointSym(const Value: IUnknown);
begin
   if supports(Value,Isymbol) then
   pPointSym:=Value as ISymbol;
end;

initialization
  TTypedComObjectFactory.Create(ComServer, TPelengRenderer, Class_PelengRenderer,
    ciMultiInstance, tmApartment);
end.