otbQgisDescriptor.cxx 12.3 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 95
  if (argc > 3)
    {
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 106
  for (unsigned int i = 0; i < nbOfParam; i++)
    {
107 108 109
    Parameter::Pointer param = appli->GetParameterByKey(appKeyList[i]);
    if (param->GetMandatory())
      {
110 111 112 113 114
	if (appli->GetParameterType(appKeyList[i]) == ParameterType_OutputImage)
	  {
	    output_parameter_name = appKeyList[i];
	    hasRasterOutput = true;
	  }
115
      }
116
    }
117
  }
118 119 120 121 122 123 124 125 126 127 128

  if(output_parameter_name.empty())
    dFile << module << std::endl;
  else
    dFile << module << "|" <<  output_parameter_name << std::endl;
  
  dFile << appli->GetDescription() << std::endl;
  dFile << group << std::endl;
  
  for (unsigned int i = 0; i < nbOfParam; i++)
    {
129
    const std::string name = appKeyList[i];
130 131
    const Parameter::Pointer param = appli->GetParameterByKey(name);
    const ParameterType type = appli->GetParameterType(name);
132
    const std::string description = appli->GetParameterName(name);
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    if (  type == ParameterType_Group  ||
          type == ParameterType_OutputProcessXML  ||
          type == ParameterType_InputProcessXML  ||
          type == ParameterType_RAM ||
          param->GetRole() == Role_Output )
      {
      // group parameter cannot have any value.
      // outxml and inxml parameters are not relevant for QGIS and is considered a bit noisy
      // 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;
153 154 155 156 157 158 159
#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())
	    {
160

161 162 163 164 165 166 167 168 169 170
	      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
171

172 173
    bool isDestination = false;
    bool isEpsgCode = false;
174

175 176 177 178 179 180 181 182 183 184
    // use QgsProcessingParameterCrs if required.
    // TODO: do a regex on name to match ==epsg || *\.epsg.\*
    if ( name == "epsg"
	      || name == "map.epsg.code"
	      || name == "mapproj.epsg.code"
	      || name == "mode.epsg.code")
        {
        qgis_type = "QgsProcessingParameterCrs";
        isEpsgCode = true;
        }
185

186
    dFile << qgis_type << "|" << name << "|" << description;
187 188

      std::string default_value = "None";
189 190 191 192 193 194 195 196 197
    if (type == ParameterType_Int)
      {
      if (isEpsgCode)
        {
          if (param->HasValue() && appli->GetParameterInt(name) < 1)
    	default_value =  "EPSG: " + appli->GetParameterAsString(name);
          else
    	default_value =  "ProjectCrs";
        }
198
      else
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        {
        dFile << "|QgsProcessingParameterNumber.Integer";
        default_value = param->HasValue() ? appli->GetParameterAsString(name): "0";
        }
      }
    else if (type == ParameterType_Float)
      {	
      dFile << "|QgsProcessingParameterNumber.Double";
      default_value = param->HasValue() ? appli->GetParameterAsString(name): "0";
      }
    else if (type == ParameterType_Radius)
      {	
      dFile << "|QgsProcessingParameterNumber.Integer";
      default_value = param->HasValue() ? appli->GetParameterAsString(name): "0";
      }
    else if(type == ParameterType_InputFilename)
      {
      // TODO: if parameter InputFilename can give supported extensions
      // we can use it gitlab #1559
218
      dFile << "|QgsProcessingParameterFile.File|None";
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
      }
    else if(type == ParameterType_Directory)
      {
      dFile << "|QgsProcessingParameterFile.Folder|False";
      }      
    else if (type == ParameterType_InputImageList)
      {
      dFile << "|3"; //QgsProcessing.TypeRaster
      }
    else if (type == ParameterType_InputVectorDataList)
      {
      dFile << "|-1"; //QgsProcessing.TypeVectorAnyGeometry
      }
    else if (type == ParameterType_InputVectorData)
      {
      dFile << "|-1"; //QgsProcessing.TypeVectorAnyGeometry
      }
    else if(type == ParameterType_InputFilenameList)
      {
      dFile << "|4"; //QgsProcessing.TypeFile"
      }
240
    else if(type == ParameterType_String)
241 242 243 244 245 246 247 248
      {
      // 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";
      }
249
    else if(type == ParameterType_StringList)
250 251 252 253 254 255 256 257 258
      {
      // 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";
      }
259
    else if (type == ParameterType_InputImage)
260 261 262
      {
      // default is None and nothing to add to dFile
      }
263
    else if(type == ParameterType_ListView)
264 265 266 267 268
      {
      // default is None and nothing to add to dFile
      }
    else if(type == ParameterType_Bool)
      {
269
      default_value = appli->GetParameterAsString(name);
270
      }
271 272 273 274 275 276
    else if(type == ParameterType_Choice)
      {
      std::vector<std::string>  key_list  = appli->GetChoiceKeys(name);
      std::string values = "";
      for( auto k : key_list)
        values += k + ";";
277

278 279 280 281 282 283 284
  	  values.pop_back();
  	  dFile << "|" << values ;
  	  ChoiceParameter *cparam = dynamic_cast<ChoiceParameter*>(param.GetPointer());
  	  default_value = std::to_string(cparam->GetValue());	  
      }
    else if(type == ParameterType_OutputVectorData ||
	          type == ParameterType_OutputImage ||
285
	          type == ParameterType_OutputFilename)
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
      {
      // No need for default_value, optional and extra fields in dFile.
      // If parameter is a destination type. qgis_type|name|description is enough.
      // So we simply set isDestination to true and skip to end to append a new line.
      isDestination =  true;
      }
    else
      {
      std::cout << "ERROR: default_value is empty for '" << name << "' type='" << qgis_type << "'" << std::endl;
      return EXIT_FAILURE;	  
      }

    if (!isDestination)
      {
      std::string optional;
      if (param->GetMandatory())
        {
        // TODO: avoid workaround for stringlist types (fix appengine)
        // type == ParameterType_StringList check is needed because:
        // If parameter is mandatory it can have no value
        // 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";
        }
              #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
    	dFile << "|" << default_value << "|" << optional;
      }
    dFile << std::endl;
    }
326

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

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

  appli = nullptr;
  ApplicationRegistry::CleanRegistry();

344
  return EXIT_SUCCESS;
345
  }
346 347