Знаю, что тему сам закрыл, но ведь обещал показать код...
Итак, если кто-то вдруг будет озадачен той же проблемой, вот классы (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;
}
}
}