ArcScene, получить координаты экрана

ArcGIS 8.x,9.x,10.x (Arcview, ArcEditor, Arcinfo).
Ответить
Lottarend
Интересующийся
Сообщения: 15
Зарегистрирован: 01 авг 2012, 08:00
Репутация: 0

ArcScene, получить координаты экрана

Сообщение Lottarend » 15 авг 2014, 03:33

Добрый день. Я делаю приложение arcScene и собственно, знаю, что координаты экрана можно сконвертировать в 3D координаты вот так

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

 ISceneGraph pSceneGraph = m_pSceneHookHelper.SceneGraph;
 IPoint pPoint;
 pSceneGraph.Locate(pSceneGraph.ActiveViewer, X, Y, esriScenePickMode.esriScenePickFastLocation, true, out pPoint, out pOwner, out pObject);
А как наоборот?
Я просто меняю координаты сконвертированной точки с помощью замыкания, а функция Locate может также вернуть слой и объект, на который указывает курсор мыши. Получается, мне нужно снова получить координаты X,Y экрана от 3D точки.
Последний раз редактировалось Lottarend 21 авг 2014, 07:43, всего редактировалось 1 раз.

Lottarend
Интересующийся
Сообщения: 15
Зарегистрирован: 01 авг 2012, 08:00
Репутация: 0

Re: ArcScene, получить координаты экрана

Сообщение Lottarend » 16 авг 2014, 04:22

Предчувствую, что никто не ответит...
Посоветуйте тогда форум, где отвечают, пожалуйста.
Два дня искал какой-нибудь пример в справке, не нашёл... может плохо искал. Помогите кто-нибудь! Я на этом застрял.

Lottarend
Интересующийся
Сообщения: 15
Зарегистрирован: 01 авг 2012, 08:00
Репутация: 0

Re: ArcScene, получить координаты экрана

Сообщение Lottarend » 17 авг 2014, 13:32

Думаю, что ту же задачу можно попробовать решить путём самостоятельной реализации функции Locate. То ли с помощью фильтра (но в 3D у меня получались неадекватные результаты), то ли как-то иначе... Смотрю в сторону IRay, можно как-то сделать проверку пересечения вектором геометрии и подсчёт дистанции от камеры до точки пересечения. Самая меньшая дистанция у того объекта, на котором стоит точка.
Я напишу здесь решение, если у меня что-то получится, но это просто обидно. 0 ответов. Даже ответа в духе "такое невозможно" нет.

[ Сообщение с мобильного устройства ]

swdartvader
Активный участник
Сообщения: 190
Зарегистрирован: 16 дек 2012, 09:08
Репутация: 48
Откуда: Калининград

Re: ArcScene, получить координаты экрана

Сообщение swdartvader » 18 авг 2014, 17:12

Оффтоп
Здесь принято отвечать по-существу, если Вы обратите внимание на ответы в других темах, то можете в этом убедиться

Аватара пользователя
paleogis
Модератор
Сообщения: 1112
Зарегистрирован: 22 мар 2009, 08:54
Репутация: 200
Ваше звание: Модератоо

Re: ArcScene, получить координаты экрана

Сообщение paleogis » 19 авг 2014, 06:12

Lottarend писал(а):Посоветуйте тогда форум,
Ну если Вам не ответили не беда, вполне возможно, что на форуме gis-lab больше активных участников, которые специализируются на открытых ГИС.
ArcGIS больше обсуждают например на форуме http://www.dataplus.ru/forum/
Из англоязычных форумов могу посоветовать http://gis.stackexchange.com/.
Наверняка, если погуглите, можете найти специализированные комьюнити по ESRI.

Lottarend
Интересующийся
Сообщения: 15
Зарегистрирован: 01 авг 2012, 08:00
Репутация: 0

Re: ArcScene, получить координаты экрана

Сообщение Lottarend » 20 авг 2014, 06:14

Спасибо за ссылки -)
Я кажется нашёл, каким образом можно получить координаты экрана, но это странное решение и не для всего годится. Смысл в том, чтобы поставить на 3D графический элемент (IMarkerSymbol). Задать свойство size очень-очень маленьким, чтобы символ закрасил как можно меньше пикселей...
Затем нужно отключить все слои, кроме слоя графики, так, чтобы на экране остался только один маркер.
Затем делается скриншот, и картинка считывается попиксельно, пока не находится пиксель с нужным цветом.
Вот они x,y координаты -) Решение странное, но пока я только так смог это реализовать.

Lottarend
Интересующийся
Сообщения: 15
Зарегистрирован: 01 авг 2012, 08:00
Репутация: 0

Re: ArcScene, получить координаты экрана

Сообщение Lottarend » 22 авг 2014, 05:26

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

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

 public class ScreenActions
    {
        delegate int forIncrement(ref int i);
        delegate bool forBool(int i, int widthOrHeight);
        IScene pScene;

        public ScreenActions(IScene pScene)
        {
            this.pScene = pScene;
        }

        /// <summary>
        /// Получает объект и слой по 3D координатам
        /// </summary>
        /// <param name="point">3D точка</param>
        /// <param name="X">Примерное расположение объекта в пикселях. 0, если неизвестно</param>
        /// <param name="Y">Примерное расположение объекта в пикселях. 0, если неизвестно</param>
        /// <returns></returns>
        public object[] GetFeatureOn3DPoint(IPoint point, int X, int Y)
        {
            IPoint pPoint;
            object pOwner = null, //слой
                pObject = null; //объект, на который указывает мышь      

            ISceneGraph pSceneGraph = pScene.SceneGraph;
            //сперва надо найти маркер
            IGraphicsContainer3D m_globeGraphicsLayer = (IGraphicsContainer3D)pScene.ActiveGraphicsLayer;
            m_globeGraphicsLayer.DeleteAllElements();
            IElement e = new MarkerElementClass();

            IMarkerSymbol symbol = new SimpleMarkerSymbol();
            IRgbColor color = new RgbColorClass();
            color.Red = 0;
            color.Green = 0;
            color.Blue = 0;
            symbol.Color = color;
            symbol.Size = 0.1;
            ((IMarkerElement)e).Symbol = symbol;
            e.Geometry = point as IPoint;
            m_globeGraphicsLayer.AddElement(e);
            pScene.SceneGraph.Invalidate(pScene.ActiveGraphicsLayer, true, false);
            pScene.SceneGraph.RefreshViewers();

            IEnumLayer enl1 = pScene.get_Layers(null, true);
            ILayer lay1 = null;
            for (enl1.Reset(); (lay1 = enl1.Next()) != null; )
            {
                lay1.Visible = false;
            }
            pScene.ActiveGraphicsLayer.Visible = true;
            System.IO.File.Delete(@"C:\Users\Sardo\1.bmp");
            pSceneGraph.ActiveViewer.GetScreenShot(esri3DOutputImageType.BMP, @"C:\Users\Sardo\1.bmp");
            enl1 = pScene.get_Layers(null, true);
            for (enl1.Reset(); (lay1 = enl1.Next()) != null; )
            {
                lay1.Visible = true;
            }
            pSceneGraph.RefreshViewers();
            int tarX = -1, tarY = -1;
            using (Bitmap bmp1 = new Bitmap(@"C:\Users\Sardo\1.bmp"))
            {
                //разблокируем биты изображения. Это класс для быстрого поиска цвета пикселя по картинке
                LockBitmap lockObject = new LockBitmap(bmp1);
                lockObject.LockBits();
                //теперь задаём с чего начинать поиск - с низа или с верха экрана (в зависомости от положения курсора)
                forIncrement incrementFunc;
                forBool boolFunc;
                int startX, startY;
                if (Y < bmp1.Height / 2)
                {
                    //идём вниз
                    incrementFunc = new forIncrement(delegate(ref int i) { return i++; });
                    boolFunc = new forBool(delegate(int i, int widthOrHeight)
                    {
                        return i < widthOrHeight;
                    });
                    startX = 0; startY = 0;
                }
                else
                {
                    //идём вверх
                    incrementFunc = new forIncrement(delegate(ref int i) { return i--; });
                    boolFunc = new forBool(delegate(int i, int widthOrHeight)
                    {
                        return i > -1;
                    });
                    startX = bmp1.Width - 1;
                    startY = bmp1.Height - 1;
                }
                for (int y = startY; boolFunc(y, bmp1.Height); incrementFunc(ref y))
                {
                    if (tarX != -1) break;
                    for (int x = startX; boolFunc(x, bmp1.Width); incrementFunc(ref x))
                    {
                        Color colorP = lockObject.GetPixel(x, y);
                        if (colorP.IsEmpty) continue;
                        int r = colorP.R;
                        int g = colorP.G;
                        int b = colorP.B;
                        if (r != 255 && (r == g && g == b && b == r))
                        {
                            pSceneGraph.Locate(pSceneGraph.ActiveViewer, x, y, esriScenePickMode.esriScenePickGraphics, true, out pPoint, out pOwner, out pObject);
                            if (pObject != null)
                            {
                                pObject = null;                             
                                pSceneGraph.Locate(pSceneGraph.ActiveViewer, x, y, esriScenePickMode.esriScenePickGeography, true, out pPoint, out pOwner, out pObject);
                                if (pObject != null)
                                {
                                    tarX = x;
                                    tarY = y;
                                    break;
                                }
                            }
                        }
                    }
                }
                lockObject.UnlockBits();
            }
            m_globeGraphicsLayer.DeleteAllElements();
            return new object[] { pObject, pOwner };
        }
    }

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

public class LockBitmap
    {
        Bitmap source = null;
        IntPtr Iptr = IntPtr.Zero;
        BitmapData bitmapData = null;

        public byte[] Pixels { get; set; }
        public int Depth { get; private set; }
        public int Width { get; private set; }
        public int Height { get; private set; }

        public LockBitmap(Bitmap source)
        {
            this.source = source;
        }

        /// <summary>
        /// Lock bitmap data
        /// </summary>
        public void LockBits()
        {
            try
            {
                // Get width and height of bitmap
                Width = source.Width;
                Height = source.Height;

                // get total locked pixels count
                int PixelCount = Width * Height;

                // Create rectangle to lock
                Rectangle rect = new Rectangle(0, 0, Width, Height);

                // get source bitmap pixel format size
                Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);

                // Check if bpp (Bits Per Pixel) is 8, 24, or 32
                if (Depth != 8 && Depth != 24 && Depth != 32)
                {
                    throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
                }

                // Lock bitmap and return bitmap data
                bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
                                             source.PixelFormat);

                // create byte array to copy pixel values
                int step = Depth / 8;
                Pixels = new byte[PixelCount * step];
                Iptr = bitmapData.Scan0;

                // Copy data from pointer to array
                Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Unlock bitmap data
        /// </summary>
        public void UnlockBits()
        {
            try
            {
                // Copy data from byte array to pointer
                Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);

                // Unlock bitmap data
                source.UnlockBits(bitmapData);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Get the color of the specified pixel
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public Color GetPixel(int x, int y)
        {
            Color clr = Color.Empty;

            // Get color components count
            int cCount = Depth / 8;

            // Get start index of the specified pixel
            int i = ((y * Width) + x) * cCount;

            if (i > Pixels.Length - cCount)
                throw new IndexOutOfRangeException();

            if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
            {
                byte b = Pixels[i];
                byte g = Pixels[i + 1];
                byte r = Pixels[i + 2];
                byte a = Pixels[i + 3]; // a
                clr = Color.FromArgb(a, r, g, b);
            }
            if (Depth == 24) // For 24 bpp get Red, Green and Blue
            {
                byte b = Pixels[i];
                byte g = Pixels[i + 1];
                byte r = Pixels[i + 2];
                clr = Color.FromArgb(r, g, b);
            }
            if (Depth == 8)
            // For 8 bpp get color value (Red, Green and Blue values are the same)
            {
                byte c = Pixels[i];
                clr = Color.FromArgb(c, c, c);
            }
            return clr;
        }

        /// <summary>
        /// Set the color of the specified pixel
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="color"></param>
        public void SetPixel(int x, int y, Color color)
        {
            // Get color components count
            int cCount = Depth / 8;

            // Get start index of the specified pixel
            int i = ((y * Width) + x) * cCount;

            if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
            {
                Pixels[i] = color.B;
                Pixels[i + 1] = color.G;
                Pixels[i + 2] = color.R;
                Pixels[i + 3] = color.A;
            }
            if (Depth == 24) // For 24 bpp set Red, Green and Blue
            {
                Pixels[i] = color.B;
                Pixels[i + 1] = color.G;
                Pixels[i + 2] = color.R;
            }
            if (Depth == 8)
            // For 8 bpp set color value (Red, Green and Blue values are the same)
            {
                Pixels[i] = color.B;
            }
        }
    }

Ответить

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

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

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