Программное создание слоя

0 голосов
спросил 01 Янв, 07 от Scok (1,260 баллов) в категории Программные продукты Esri
    Доброе время суток!
Подскажите, возможно ли программно в ArcMap создать пустой слой. И вообще как его создавать - чего-то я немного запутался. В качестве начального условия: имеется IMxDocument на текущий документ, загруженный в ArcMap.
Спасибо!

17 Ответы

0 голосов
ответил 09 Янв, 07 от Scok (1,260 баллов)
Что ж, подход "в лоб" привел к тому, что пустой слой в ArcMAP не создать, ибо слой - это графическое представление данных. То есть, пустой слой - это пустой класс объектов (простых или пространственных). Потому, чтобы не лезть в базу геоданных пришлось создавать пустой шейп-файл и уже на его основе делать слой. Создавал шейп-файл так:
HRESULT CoDBSA::CreateShapeFile(String *Name,IGeometry *ipGeom)
{
System::String *pathFolder = S"C:\\Temp\\";
ESRI::ArcGIS::Geodatabase::IWorkspaceFactory *ipWSF;
ESRI::ArcGIS::Geodatabase::IFeatureWorkspace *ipFWS;
ESRI::ArcGIS::Geodatabase::IFields *ipFs;
ESRI::ArcGIS::Geodatabase::IField *ipF;
ESRI::ArcGIS::Geodatabase::IFieldsEdit *ipFsE;
ESRI::ArcGIS::Geodatabase::IFieldEdit *ipFE;
ESRI::ArcGIS::Geodatabase::IGeometryDef *ipGeomDef;
ESRI::ArcGIS::Geodatabase::IGeometryDefEdit *ipGeomDefEdit;
ESRI::ArcGIS::Geodatabase::IFeatureClass *ipFC;
ESRI::ArcGIS::Geometry::ISpatialReference *ipSR;
ESRI::ArcGIS::Geodatabase::esriFieldType FType;
ESRI::ArcGIS::Geometry::esriGeometryType GeomType;
ESRI::ArcGIS::Geodatabase::esriFeatureType FeatType;

// проверка на наличие геометрии
if(ipGeom == NULL || ipGeom->IsEmpty == true) // геометрия пустая
     {
      FType = ESRI::ArcGIS::Geodatabase::esriFieldTypeGeometry;
      GeomType = ESRI::ArcGIS::Geometry::esriGeometryPolygon;
      ipSR = new ESRI::ArcGIS::Geometry::UnknownCoordinateSystemClass();
     }
else // геометрия не пустая - заполнение параметров shape-файла из геометрии
     {
      FType = ESRI::ArcGIS::Geodatabase::esriFieldTypeGeometry;
      GeomType = ipGeom->get_GeometryType();
      ipSR = ipGeom->get_SpatialReference();
     }

// открытие директории, в которой будет создан Shapefile
ipWSF = new ESRI::ArcGIS::DataSourcesFile::ShapefileWorkspaceFactoryClass();
ipFWS = (IFeatureWorkspace*)ipWSF->OpenFromFile(pathFolder,0);
mIpWS = (IWorkspace*)ipFWS;

// создание и инициализация коллекции полей
ipFs = new ESRI::ArcGIS::Geodatabase::FieldsClass();
ipF = new ESRI::ArcGIS::Geodatabase::FieldClass();
ipFsE = (IFieldsEdit*)ipFs;

// создание поля геометрии
ipFE = (IFieldEdit*) ipF;
ipFE->set_Name(S"Shape");
ipFE->set_Type(FType);

ipGeomDef = new ESRI::ArcGIS::Geodatabase::GeometryDefClass();
ipGeomDefEdit = (IGeometryDefEdit*)ipGeomDef;
ipGeomDefEdit->set_GeometryType(GeomType);
ipGeomDefEdit->set_SpatialReference(ipSR);

ipFE->set_GeometryDef(ipGeomDef);
ipFsE->AddField(ipF);

// создание Shape-файла
FeatType = ESRI::ArcGIS::Geodatabase::esriFTSimple;
try{ipFC = ipFWS->CreateFeatureClass(Name,ipFs,0,0,FeatType,S"Shape",S"");}
catch(Exception *Ex){return -1;}

return S_OK;
}
0 голосов
ответил 09 Янв, 07 от Scok (1,260 баллов)
Ну и, добавлял его в ArcMAP так:
//=== I === добавление нового слоя в ArcMAP ===================================
HRESULT CoAMSA::AddLayer_geometry(String *LayerName,IGeometry *ipGeom)
{
long Count;
HRESULT hr;
String *Path;
ESRI::ArcGIS::Geodatabase::IWorkspaceFactory *ipWSF;
ESRI::ArcGIS::Geodatabase::IFeatureWorkspace *ipFWS;
ESRI::ArcGIS::Geodatabase::IFeatureClass *ipFC;
ESRI::ArcGIS::Carto::IFeatureLayer *ipFL;


// создание Shape-файла
ipDBSA = new DBSA::CoDBSA();
hr = ipDBSA->CreateShapeFile(LayerName,ipGeom);
if(hr != S_OK) return hr;

// создание слоя на основе Shape-файла
Path = S"C:\\Temp\\";
ipWSF = new ESRI::ArcGIS::DataSourcesFile::ShapefileWorkspaceFactoryClass();
ipFWS = (IFeatureWorkspace*)ipWSF->OpenFromFile(Path,0);
ipFC = ipFWS->OpenFeatureClass(LayerName);

ipFL = new ESRI::ArcGIS::Carto::FeatureLayerClass();
ipFL->set_FeatureClass(ipFC);
ipFL->set_Name(LayerName);
m_ipFL = ipFL;

return S_OK;
}
0 голосов
ответил 12 Янв, 07 от Alexander_Vishn (1,900 баллов)
Scok, большое спасибо!. Очень помог! :)
Порт на c#, быть может куму нужно будет.
public static class Factoty
    {
        public static void CreateShapeFile(String name, IGeometry ipGeom)
        {
            String pathFolder = "c:\\Temp\\";
            IWorkspaceFactory ipWSF;
            IFeatureWorkspace ipFWS;
            IFields ipFs;
            IField ipF;
            IFieldsEdit ipFsE;
            IFieldEdit ipFE;
            IGeometryDef ipGeomDef;
            IGeometryDefEdit ipGeomDefEdit;
            IFeatureClass ipFC;
            ISpatialReference ipSR;
            esriFieldType FType;
            esriGeometryType GeomType;
            esriFeatureType FeatType;
            IWorkspace mIpWS;

            try
            {
               if (ipGeom == null || ipGeom.IsEmpty == true) // геометрия пустая
               {
                    FType = esriFieldType.esriFieldTypeGeometry;
                    GeomType = esriGeometryType.esriGeometryPoint;
                    ipSR = new UnknownCoordinateSystemClass();
               }
               else // геометрия не пустая - заполнение параметров shape-файла из геометрии
               {
                    FType = esriFieldType.esriFieldTypeGeometry;
                    GeomType = ipGeom.GeometryType;
                    ipSR = ipGeom.SpatialReference;
               }

               ipWSF = new ShapefileWorkspaceFactoryClass();
               ipFWS = (IFeatureWorkspace)ipWSF.OpenFromFile(pathFolder, 0);
               mIpWS = (IWorkspace)ipFWS;

               ipFs = new FieldsClass();
               ipF = new FieldClass();
               ipFsE = (IFieldsEdit)ipFs;

               ipFE = (IFieldEdit)ipF;

               ipFE.Name_2 = "Shape";
               ipFE.Type_2 = FType;

               ipGeomDef = new GeometryDefClass();
               ipGeomDefEdit = (IGeometryDefEdit)ipGeomDef;
               ipGeomDefEdit.GeometryType_2 = GeomType;
               ipGeomDefEdit.SpatialReference_2 = ipSR;

               ipFE.GeometryDef_2 = ipGeomDef;
               ipFsE.AddField(ipF);

               FeatType = esriFeatureType.esriFTSimple;
               ipFC = ipFWS.CreateFeatureClass(name, ipFs,
                                                null, null, FeatType, "Shape", "");

            }
            catch (Exception _ex)
            {
               throw;
            }
        }
    }

Пользовать так:
try
               {
                    Factoty.CreateShapeFile("MyFile2", null);

                    String Path;
                    IWorkspaceFactory ipWSF;
                    IFeatureWorkspace ipFWS;
                    IFeatureClass ipFC;
                    IFeatureLayer ipFL;

                    String LayerName = "MyFile2";

    &nbs
0 голосов
ответил 12 Янв, 07 от Scok (1,260 баллов)
Всегда рад помочь - если могу... :)

Опыт показал, что корректнее использовать метод создания Shape-файла в следующем виде:
HRESULT CreateShapeFile(String *LayerName,String *FolderPath,ISpatialReference *ipSR,esriGeometryType GeomType);

Как я ни старался "упаковать" передаваемые параметры в один объект - все равно получилось с таким прототипом. Обычно геометрии читаются в цикле и потому неудобно перед циклом считать геометрию, чтобы метод взял из нее все чего ему нужно...
    
0 голосов
ответил 15 Янв, 07 от Alexander_Vishn (1,900 баллов)
Сделай итератор по геометрии и передавай его :)
А ты с растрами не работал?. задача та же самая - создание растра. Посмотрел семплы.
RasterWorkspaceFactoryClass ipWSF = new RasterWorkspaceFactoryClass();
               IRasterWorkspace ipFWS = (IRasterWorkspace)ipWSF.OpenFromFile("c:\\Temp\\", 0);

Но для дальнейших операций нужен IRasterWorkspaceEx, который никак не могу ниоткуда взять. :)
IRasterWorkspaceEx tmp = ipFWS as IRasterWorkspaceEx дает null. Куда копать пока не наю.
0 голосов
ответил 18 Янв, 07 от Scok (1,260 баллов)
Что бы добить эту тему до логического завершения хотелось бы сказать пару слов о программном удалении Shape-файла. По наивности и русскому менталитету (то бишь инструкции читаем при жесткой необходимости...) эта операция решалась так:
// удаление файлов, если они существуют
ExistFlag = System::IO::File::Exists(SFile1);
if(ExistFlag == true) System::IO::File::Delete(SFile1);

Все было хорошо, пока Shape-файлы не начали редактироваться... В этом случае ArcMAP удерживал хендлы открытого Shape-файла пока сам не закрывался - как следствие, File::Delete() заканчивался с исключительной ситуацией и shape-файл оставался себе во временной папке.
0 голосов
ответил 18 Янв, 07 от Scok (1,260 баллов)
А вот как надо было это делать:
m_ipFL - IFeatureLayer - это указатель на созданный Shape-файл. Итак,
HRESULT <имя класса>::DeleteShapeFile()
{
ESRI::ArcGIS::Geodatabase::IDataset *ipDS;

// проверка на наличие Shape-файла
if(m_ipFL == 0) return 100003;

// удаление слоя из ArcMAP
DeleteLayerFromArcMAP();

ipDS = (ESRI::ArcGIS::Geodatabase::IDataset*)m_ipFL->get_FeatureClass();
if(ipDS->CanDelete())ipDS->Delete();
}

и

HRESULT <имя файла>::DeleteLayerFromArcMAP()
{
int cmp,flag;
long LayersCount,i;
System::String *LayerName,*str;
ESRI::ArcGIS::Carto::IMap *ipMap;
ESRI::ArcGIS::Carto::ILayer *ipLayer;

// проверка на наличие Shape-файла
if(m_ipFL == 0) return 100003;

// получение имени Shape-файла
LayerName = m_ipFL->get_Name();

// поиск слоя в ArcMAP
ipMap = m_ipMxDoc->get_FocusMap();
LayersCount = ipMap->get_LayerCount();
flag = 0;
for(i=0;i<LayersCount;i++)
     {
      ipLayer = ipMap->get_Layer(i);
      str = ipLayer->get_Name();
      cmp = System::String::Compare(LayerName,str);
      if(cmp == 0) {flag = 1; break;}
     }

if(flag == 1)               // слой загружен в ArcMAP
     {
      ipMap->DeleteLayer((ILayer*)m_ipFL);
     }
else return 100005;          // слой не найден -> удалять из ArcMAP нечего -> выход с ошибкой

return S_OK;
}

Ну вот, теперь вроде все. Удачи.
0 голосов
ответил 19 Янв, 07 от Alexander_Vishn (1,900 баллов)
Прива. В коде упоминнается tmp-папка как
System::String *pathFolder = S"C:\\Temp\\";
не в курсе как узнать дефолтовую темп-папку(и) аргиса?
0 голосов
ответил 21 Янв, 07 от Scok (1,260 баллов)
Никогда такого вопроса у меня не появлялось. Но, по-моему ArcGIS использует переменные окружения Windows. Еще чего-то мне припоминается, что во время установки указывается папка для Workspace.
0 голосов
ответил 21 Янв, 07 от Alexander_Vishn (1,900 баллов)
Гы. :) и что же ты делаешь, когда на компе нету  S"C:\\Temp\\"? )))))
Добро пожаловать на сайт Вопросов и Ответов, где вы можете задавать вопросы по GIS тематике и получать ответы от других членов сообщества.
...