otbQgisDescriptor.cxx 12.4 KB
Newer Older
1
/*
Julien Michel's avatar
Julien Michel committed
2
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperChoiceParameter.h"
#include "otbWrapperListViewParameter.h"
#include "otbWrapperBoolParameter.h"
#include "otbWrapperApplicationRegistry.h"

#include <iostream>
#include <cassert>
#include <fstream>

int main(int argc, char* argv[])
{
  if (argc < 3)
    {
34 35
    std::cerr << "Usage : " << argv[0] << " name OTB_APPLICATION_PATH [out_dir]" << std::endl;
    return EXIT_FAILURE;
36 37 38
    }
    
  using namespace otb::Wrapper;
39

40 41 42 43 44 45 46 47 48
  const std::string module(argv[1]);

  /* TestApplication is removed in CMakeLists.txt */
#if 0
  if (module == "TestApplication")
    return EXIT_SUCCESS;
#endif

  ApplicationRegistry::AddApplicationPath(argv[2]);
49
  Application::Pointer appli =  ApplicationRegistry::CreateApplicationFaster(module);
50 51 52
  
  assert(!appli.IsNull());

53 54 55
  const std::string group = appli->GetDocTags().size() > 0 ? appli->GetDocTags()[0] : "";
  assert(!group.empty());

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
  std::map<ParameterType, std::string> parameterTypeToString;
  parameterTypeToString[ParameterType_Bool] = "QgsProcessingParameterBoolean";
  parameterTypeToString[ParameterType_Int] = "QgsProcessingParameterNumber";
  parameterTypeToString[ParameterType_Float] = "QgsProcessingParameterNumber";
  parameterTypeToString[ParameterType_RAM] = "QgsProcessingParameterNumber";
  parameterTypeToString[ParameterType_Radius] = "QgsProcessingParameterNumber";
  parameterTypeToString[ParameterType_Choice] = "OTBParameterChoice";
  parameterTypeToString[ParameterType_String] = "QgsProcessingParameterString";
  parameterTypeToString[ParameterType_InputImage] = "QgsProcessingParameterRasterLayer";
  parameterTypeToString[ParameterType_InputFilename] = "QgsProcessingParameterFile";
  parameterTypeToString[ParameterType_InputImageList] = "QgsProcessingParameterMultipleLayers";
  parameterTypeToString[ParameterType_InputVectorData] = "QgsProcessingParameterVectorLayer";
  parameterTypeToString[ParameterType_InputFilenameList] = "QgsProcessingParameterMultipleLayers";
  parameterTypeToString[ParameterType_InputVectorDataList] = "QgsProcessingParameterMultipleLayers";
  parameterTypeToString[ParameterType_OutputImage] = "QgsProcessingParameterRasterDestination";
  parameterTypeToString[ParameterType_OutputVectorData] = "QgsProcessingParameterVectorDestination";
  parameterTypeToString[ParameterType_OutputFilename] = "QgsProcessingParameterFileDestination";
  parameterTypeToString[ParameterType_Directory] = "QgsProcessingParameterFile";
Rashad Kanavath's avatar
Rashad Kanavath committed
74
  // TODO
75
  parameterTypeToString[ParameterType_StringList] = "QgsProcessingParameterString";
Rashad Kanavath's avatar
Rashad Kanavath committed
76 77 78 79 80
  // ListView parameters are treated as plain string (QLineEdit) in qgis processing ui.
  // This seems rather unpleasant when comparing Qgis processing with Monteverdi/Mapla in OTB
  // We tried to push something simple with checkboxes but its too risky for this version
  // and clock is ticking...

81 82
  parameterTypeToString[ParameterType_ListView] = "QgsProcessingParameterString";

Rashad Kanavath's avatar
Rashad Kanavath committed
83 84
  // For next update of plugin code ListView should use a custom widget wrapper and behave
  // exactly like OTB Mapla. And this #if 0 block is our TODO remainder.
85 86 87
  #if 0
  parameterTypeToString[ParameterType_ListView] = "OTBParameterListView";
  #endif
88 89 90 91

  const std::vector<std::string> appKeyList = appli->GetParametersKeys(true);
  const unsigned int nbOfParam = appKeyList.size();

92 93
  std::string output_file = module + ".txt";
  std::string  algs_txt = "algs.txt";
94
  if ( argc > 3 )
95
    {
96 97
    output_file = std::string(argv[3]) + module + ".txt";
    algs_txt = std::string(argv[3])  +  "algs.txt";
98
    }
99
  std::ofstream dFile;
100
  dFile.open (output_file, std::ios::out);
101 102 103

  std::string output_parameter_name;
  bool hasRasterOutput = false;
104
  {
105
  for ( unsigned int i = 0; i < nbOfParam; i++ )
106
    {
107 108
    Parameter::Pointer param = appli->GetParameterByKey( appKeyList[i] );
    if ( param->GetMandatory() )
109
      {
110
	if ( appli->GetParameterType( appKeyList[i] ) == ParameterType_OutputImage )
111 112 113 114
	  {
	    output_parameter_name = appKeyList[i];
	    hasRasterOutput = true;
	  }
115
      }
116
    }
117
  }
118

119
  if( output_parameter_name.empty() )
120 121 122 123 124 125
    dFile << module << std::endl;
  else
    dFile << module << "|" <<  output_parameter_name << std::endl;
  
  dFile << appli->GetDescription() << std::endl;
  dFile << group << std::endl;
126 127 128 129 130 131 132 133 134

  /*
  From here onwards each line appended to dFile is passed to QgsProcessingParameter* class constructor.
  dFile is nothing but a csv (with a .txt) with "|" as delimiter character.
  First field is the name of Qgis parameter class and rest of it are extracted as list and passed to class constructor.
  Parsing and calling of paramater classes are done by python.
  source available : qgis/python/plugins/processing/core/parameters.py
  source code of qgis parameter is available at: qgis/src/core/processing/qgsprocessingparameters.cpp
  */
135
  
136
  for ( unsigned int i = 0; i < nbOfParam; i++ )
137
    {
138
    const std::string name = appKeyList[i];
139 140
    const Parameter::Pointer param = appli->GetParameterByKey(name);
    const ParameterType type = appli->GetParameterType(name);
141
    const std::string description = appli->GetParameterName(name);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    if (  type == ParameterType_Group  ||
          type == ParameterType_RAM ||
          param->GetRole() == Role_Output )
      {
      // group parameter cannot have any value.
      // ram is added by qgis-otb processing provider plugin as an advanced parameter for all apps
      // parameter role cannot be of type Role_Output
      continue;
      }
    auto it = parameterTypeToString.find(type);
    assert(  it != parameterTypeToString.end() );
    if( it == parameterTypeToString.end() )
      {
      std::cerr << "No mapping found for parameter '" <<name <<"' type=" << type << std::endl;
      return EXIT_FAILURE;
      }
    std::string qgis_type = it->second;
159 160 161 162 163 164 165
#if 0
      if (type == ParameterType_ListView)
	{
	  ListViewParameter *lv_param = dynamic_cast<ListViewParameter*>(param.GetPointer());
	  std::cerr << "lv_param->GetSingleSelection()" << lv_param->GetSingleSelection() << std::endl;
	  if (lv_param->GetSingleSelection())
	    {
166

167 168 169 170 171 172 173 174 175 176
	      qgis_type = "QgsProcessingParameterEnum";
	      std::vector<std::string>  key_list  = appli->GetChoiceKeys(name);
	      std::string values = "";
	      for( auto k : key_list)
		values += k + ";";
	      values.pop_back();
	      dFile << "|" << values ;
	    }
	}
#endif
177

178
    bool isEpsgCode = false;
179

180 181 182
    // use QgsProcessingParameterCrs if required.
    // TODO: do a regex on name to match ==epsg || *\.epsg.\*
    if ( name == "epsg"
183 184 185
	    || name == "map.epsg.code"
	    || name == "mapproj.epsg.code"
	    || name == "mode.epsg.code" )
186 187 188 189
        {
        qgis_type = "QgsProcessingParameterCrs";
        isEpsgCode = true;
        }
190

191
    dFile << qgis_type << "|" << name << "|" << description;
192 193

      std::string default_value = "None";
194
    if ( type == ParameterType_Int )
195
      {
196
      if ( isEpsgCode )
197 198 199 200 201 202
        {
          if (param->HasValue() && appli->GetParameterInt(name) < 1)
    	default_value =  "EPSG: " + appli->GetParameterAsString(name);
          else
    	default_value =  "ProjectCrs";
        }
203
      else
204 205 206 207 208
        {
        dFile << "|QgsProcessingParameterNumber.Integer";
        default_value = param->HasValue() ? appli->GetParameterAsString(name): "0";
        }
      }
209
    else if ( type == ParameterType_Float )
210 211 212 213
      {	
      dFile << "|QgsProcessingParameterNumber.Double";
      default_value = param->HasValue() ? appli->GetParameterAsString(name): "0";
      }
214
    else if ( type == ParameterType_Radius )
215 216 217 218
      {	
      dFile << "|QgsProcessingParameterNumber.Integer";
      default_value = param->HasValue() ? appli->GetParameterAsString(name): "0";
      }
219
    else if ( type == ParameterType_InputFilename )
220 221 222
      {
      // TODO: if parameter InputFilename can give supported extensions
      // we can use it gitlab #1559
223
      dFile << "|QgsProcessingParameterFile.File|None";
224
      }
225
    else if( type == ParameterType_Directory )
226 227 228
      {
      dFile << "|QgsProcessingParameterFile.Folder|False";
      }      
229
    else if ( type == ParameterType_InputImageList )
230 231 232
      {
      dFile << "|3"; //QgsProcessing.TypeRaster
      }
233 234 235
    else if ( type == ParameterType_InputVectorDataList
           || type == ParameterType_InputVectorData
           || type == ParameterType_OutputVectorData )
236 237 238
      {
      dFile << "|-1"; //QgsProcessing.TypeVectorAnyGeometry
      }
239
    else if ( type == ParameterType_InputFilenameList )
240 241 242
      {
      dFile << "|4"; //QgsProcessing.TypeFile"
      }
243
    else if ( type == ParameterType_String )
244 245 246 247 248 249 250 251
      {
      // Below line is interpreted in qgis processing as
      // 1. default_value = None
      // 2. multiLine = False
      // For more details,
      // please refer to documetation of QgsProcessingParameterString.
      default_value = "None|False";
      }
252
    else if(type == ParameterType_StringList)
253 254 255 256 257 258 259 260 261
      {
      // Below line is interpreted in qgis processing as
      // 1. default_value = None
      // 2. multiLine = True
      // For more details,
      // please refer to documetation of QgsProcessingParameterString.
      // setting default_value this way is an exception for ParameterType_StringList and ParameterType_String
      default_value = "None|True";
      }
262
    else if (type == ParameterType_InputImage || type == ParameterType_OutputImage)
263 264 265
      {
      // default is None and nothing to add to dFile
      }
266 267 268 269 270 271
    else if (type == ParameterType_OutputFilename)
      {
      // fileFilter and defaultValue is None
      // OTB does not have any implementation for file extension.
	default_value = "None|None";
      }
272
    else if(type == ParameterType_ListView)
273 274 275 276 277
      {
      // default is None and nothing to add to dFile
      }
    else if(type == ParameterType_Bool)
      {
278
      default_value = appli->GetParameterAsString(name);
279
      }
280 281 282 283 284 285
    else if(type == ParameterType_Choice)
      {
      std::vector<std::string>  key_list  = appli->GetChoiceKeys(name);
      std::string values = "";
      for( auto k : key_list)
        values += k + ";";
286

287 288 289 290 291 292 293 294 295 296 297
  	  values.pop_back();
  	  dFile << "|" << values ;
  	  ChoiceParameter *cparam = dynamic_cast<ChoiceParameter*>(param.GetPointer());
  	  default_value = std::to_string(cparam->GetValue());	  
      }
    else
      {
      std::cout << "ERROR: default_value is empty for '" << name << "' type='" << qgis_type << "'" << std::endl;
      return EXIT_FAILURE;	  
      }

298
    std::string optional;
299
    if ( param->GetMandatory() )
300
      {
301 302
      // TODO: avoid workaround for stringlist types (fix appengine)
      // type == ParameterType_StringList check is needed because:
303
      // If parameter is  mandatory it can have no value
304 305 306 307 308 309 310 311 312
      // It is accepted in OTB that, string list could be generated dynamically
      // qgis has no such option to handle dynamic values yet..
      // So mandatory parameters whose type is StringList is considered optional
      optional = param->HasValue() || type == ParameterType_StringList  ? "True" : "False";
      }
    else
      {
      optional = "True";
      }
313 314 315 316 317 318 319
              #if 0
    	  std::cerr << name;
    	  std::cerr << " mandatory=" << param->GetMandatory();
    	  std::cerr << " HasValue=" << param->HasValue();
    	  std::cerr << " qgis_type=" << qgis_type;
    	  std::cerr << " optional=" << optional << std::endl;
              #endif
320
    dFile << "|" << default_value << "|" << optional;
321 322
    dFile << std::endl;
    }
323

324 325
  if(hasRasterOutput)
    {
326
    dFile << "*QgsProcessingParameterEnum|outputpixeltype|Output pixel type|uint8;int;float;double|False|2|True" << std::endl;
327
    }
328

329
  std::cerr << "Writing " << output_file << std::endl;
330
  dFile.close();
331 332
  
  std::ofstream indexFile;
333
  indexFile.open (algs_txt, std::ios::out | std::ios::app );
334 335
  indexFile << group << "|" << module << std::endl;
  indexFile.close();
336
  std::cerr << "Updated " << algs_txt << std::endl;
337 338 339 340

  appli = nullptr;
  ApplicationRegistry::CleanRegistry();

341
  return EXIT_SUCCESS;
342
  }
343 344