bool Interpolation::print_DEM_on_file(std::string name_file, Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> demRM)
{
	StepResource pStep("Writing DEM on a text file", "app", "c0c1c382-1f1e-11e4-b0cb-b2227cce2b54");
	ProgressResource pResource("ProgressBar");
	Progress *pProgress = pResource.get(); 
    pProgress-> setSettingAutoClose(true);
	
	std::ofstream dem_file;
	dem_file.open (name_file);
    dem_file << "DEM generated from the input LAS file\n";
	dem_file << "i" << '\t' << "j" << '\t' << "z(i,j)" << '\n';  
	for (int row = 0; row < demRM.rows(); row++)
	{
			for (int col = 0; col <demRM.cols(); col++)
			{
				dem_file << row << '\t' << col << '\t' << demRM(row, col) << '\n';  
			}
			pProgress->updateProgress("Writing DEM ("+ name_file + ") on a text file", row * 100 / demRM.rows(), NORMAL);
	}
	dem_file.close();

    pProgress->updateProgress("DEM text file written.", 100, NORMAL);
	pStep->finalize();
	return true;
}
Example #2
0
std::vector<boost::uint8_t> reconstruct_icon(pgroup_icon_directory directory, const std::vector<pResource>& resources)
{
	std::vector<boost::uint8_t> res;

	if (directory == nullptr) {
		return res;
	}

	unsigned int header_size = 3 * sizeof(boost::uint16_t) + directory->Count * sizeof(group_icon_directory_entry);
	res.resize(header_size);
	memcpy(&res[0], directory.get(), 3 * sizeof(boost::uint16_t));

	for (int i = 0; i < directory->Count; ++i)
	{
		// Locate the RT_ICON with a matching ID.
		pResource icon = pResource();
		for (auto it = resources.begin(); it != resources.end(); ++it)
		{
			if ((*it)->get_id() == directory->Entries[i]->Id)
			{
				icon = *it;
				break;
			}
		}
		if (icon == nullptr)
		{
			PRINT_ERROR << "Could not locate RT_ICON with ID " << directory->Entries[i]->Id << "!" << DEBUG_INFO << std::endl;
			res.clear();
			return res;
		}

		shared_bytes icon_bytes = icon->get_raw_data();
		memcpy(&res[3 * sizeof(boost::uint16_t) + i * sizeof(group_icon_directory_entry)],
			   directory->Entries[i].get(),
			   sizeof(group_icon_directory_entry) - sizeof(boost::uint32_t)); // Don't copy the last field.
		// Fix the icon_directory_entry with the offset in the file instead of a RT_ICON id
		unsigned int size_fix = res.size();
		memcpy(&res[3 * sizeof(boost::uint16_t) + (i+1) * sizeof(group_icon_directory_entry) - sizeof(boost::uint32_t)],
			   &size_fix,
			   sizeof(boost::uint32_t));
		// Append the icon bytes at the end of the data
		if (directory->Type == 1) { // General case for icons
			res.insert(res.end(), icon_bytes->begin(), icon_bytes->end());
		}
		else if (icon_bytes->size() > 2 * sizeof(boost::uint16_t)) { // Cursors have a "hotspot" structure that we have to discard to create a valid ico.
			res.insert(res.end(), icon_bytes->begin() + 2 * sizeof(boost::uint16_t), icon_bytes->end());
		}
		else { // Invalid cursor.
			res.clear();
		}
	}

	return res;
}
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Interpolation::generate_DEM(PointCloudElement* pElement, float post_spacing) 
{
	   StepResource pStep("Generating DEM", "app", "ffe16048-1e58-11e4-b4be-b2227cce2b54");
	   
	   ProgressResource pResource("ProgressBar");
	   Progress *pProgress = pResource.get(); 
	   pProgress-> setSettingAutoClose(true);

	   Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> demRM;// dem stored in a Row major eigen matrix

	   /* Main processing loop */
	   FactoryResource<PointCloudDataRequest> req;
	   req->setWritable(true);
	   PointCloudAccessor acc(pElement->getPointCloudAccessor(req.release()));
	   if (!acc.isValid())
	   {
		   interpolation_msg += "Unable to write to point cloud for generating DEM.\n";
		   pProgress->updateProgress("Unable to write to point cloud for generating DEM.", 0, ERRORS);
		   pStep->finalize(Message::Abort, interpolation_msg);
		   return demRM.matrix(); // in this way it should return NULL matrix, see http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html: Matrix(): For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix is called a null matrix. This constructor is the unique way to create null matrices: resizing a matrix to 0 is not supported.
	   }
	   const PointCloudDataDescriptor* pDesc = static_cast<const PointCloudDataDescriptor*>(pElement->getDataDescriptor());
	   double xMin = pDesc->getXMin() * pDesc->getXScale() + pDesc->getXOffset();
	   double xMax = pDesc->getXMax() * pDesc->getXScale() + pDesc->getXOffset();
	   double yMin = pDesc->getYMin() * pDesc->getYScale() + pDesc->getYOffset();
	   double yMax = pDesc->getYMax() * pDesc->getYScale() + pDesc->getYOffset();

	   int mDim = static_cast<int>(std::ceil((xMax - xMin) / post_spacing));  //columns
	   int nDim = static_cast<int>(std::ceil((yMax - yMin) / post_spacing)); //rows
	   xMax = xMin + mDim * post_spacing;
	   yMin = yMax - nDim * post_spacing;

	   const float badVal = -9999.f;
	   demRM.setConstant(nDim, mDim, badVal);

	   int prog = 0;
	   uint32_t adv = pDesc->getPointCount() / 100;
	   for (size_t idx = 0; idx < pDesc->getPointCount(); ++idx)
	   {
		  if (!acc.isValid())
		  {
			  interpolation_msg += "Unable to access data for generating DEM.\n";
			  pProgress->updateProgress("Unable to access data for generating DEM.", 0, ERRORS);
			  pStep->finalize(Message::Abort, interpolation_msg);
			  return demRM.matrix();// in this way it should return NULL matrix, see http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html: Matrix(): For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix is called a null matrix. This constructor is the unique way to create null matrices: resizing a matrix to 0 is not supported.
		  }
		  if (idx % adv == 0)
		  {
			  pProgress->updateProgress("Generating DEM", ++prog, NORMAL);
		  }
		  if (!acc->isPointValid())
		  {
			 acc->nextValidPoint();
			 continue;
		  }
		  double x = acc->getXAsDouble(true);
		  double y = acc->getYAsDouble(true);
		  float z = static_cast<float>(acc->getZAsDouble(true));
		  
		  // calculate nearest DEM point
		  int xIndex = std::max(0, static_cast<int>(std::floor((x - xMin) / post_spacing)));
		  int yIndex = std::max(0, static_cast<int>(std::floor((yMax - y) / post_spacing)));
		  
		  float demVal = demRM(yIndex, xIndex);
		  if (demVal == badVal || demVal < z)
		  {
			 demRM(yIndex, xIndex) = z; 
		  }

		  acc->nextValidPoint();
	   }
	   pProgress->updateProgress("DEM generation is complete.", 100, NORMAL);
	   pStep->finalize();
	   return demRM;
}
bool Segmentation::Ransac_for_buildings(float dem_spacing, double ransac_threshold, cv::Mat original_tiles_merged)
{   
	StepResource pStep("Computing RANSAC on all the identified buildings", "app", "a2beb9b8-218e-11e4-969b-b2227cce2b54");
	   
	ProgressResource pResource("ProgressBar");
	Progress *pProgress = pResource.get(); 
	pProgress-> setSettingAutoClose(true);
	pProgress->updateProgress("Computing RANSAC on all buildings", 0, NORMAL);
	Ransac_buildings = Ransac(Segmentation::path);
	cv::Mat roof_image = cv::Mat::zeros(original_tiles_merged.size(), CV_8UC3);
		
	buildingS.resize(blobs.size());
	buildingS_inliers.resize(blobs.size());
	buildingS_outliers.resize(blobs.size());
	buildingS_plane_coefficients.resize(blobs.size());
	buldingS_number_inliers.resize(blobs.size());

	std::ofstream building_file;
	std::ofstream cont_file;
	cont_file.open (std::string(path) + "/Results/Number_of_RANSAC_applications.txt"); 
	for(int i = 0; i < blobs.size(); i++)
	{// i index is the building (blob) index
		pProgress->updateProgress("Computing RANSAC on all buildings\nBuilding "+ StringUtilities::toDisplayString(i) + " on "+ StringUtilities::toDisplayString(blobs.size()), static_cast<double>(static_cast<double>(i)/blobs.size()*100), NORMAL);
		building_file.open (std::string(path) + "/Results/Building_" + StringUtilities::toDisplayString(i)+".txt");
		building_file << 'i' << '\t' << 'j' << '\t' << 'X' << '\t' << 'Y' << '\t' << 'Z' << '\n'; 
		buildingS[i].setConstant(blobs[i].size(), 3, 0.0);
		
		// the j loop retrieves the  X, Y, Z coordinate for each pixel of all the buildings
		for(int j = 0; j < blobs[i].size(); j++) 
		{// j index is the pixel index for the single building
		 // loop on all the pixel of the SINGLE building
		    int pixel_column = blobs[i][j].x;
            int pixel_row = blobs[i][j].y;			

			double x_building =  pixel_column * dem_spacing;// xMin + pixel_column * dem_spacing // object coordinate 
			double y_building =  pixel_row * dem_spacing;// yMin + pixel_row * dem_spacing // object coordinate
			double z_building = original_tiles_merged.at<float>(pixel_row, pixel_column);//object coordinate
			
			buildingS[i](j,0) = x_building;
			buildingS[i](j,1) = y_building;
			buildingS[i](j,2) = z_building;
			 
			building_file << pixel_row+1 <<  '\t' << pixel_column+1 <<  '\t' << buildingS[i](j,0) << '\t' << buildingS[i](j,1) << '\t' << buildingS[i](j,2) << '\n'; //+1 on the imae coordinates to verify with opticks' rasters (origin is 1,1)
		}

		building_file.close();

		std::ofstream inliers_file;
		std::ofstream parameters_file;
		inliers_file.open (std::string(path) + "/Results/Inliers_building_" + StringUtilities::toDisplayString(i)+".txt");
		parameters_file.open (std::string(path) + "/Results/plane_parameters_building_" + StringUtilities::toDisplayString(i)+".txt");
		//parameters_file << "a\tb\tc\td\tmean_dist\tstd_dist\n";
		int cont = 0;
		Ransac_buildings.ransac_msg += "\n____________Building number " + StringUtilities::toDisplayString(i) +"____________\n";
		Ransac_buildings.ransac_msg += "\nITERATION NUMBER " + StringUtilities::toDisplayString(cont) +"\n";
		Ransac_buildings.ComputeModel(buildingS[i], ransac_threshold);
		
		buldingS_number_inliers[i]= Ransac_buildings.n_best_inliers_count;
		buildingS_inliers[i] = Ransac_buildings.final_inliers;
		buildingS_outliers[i] = Ransac_buildings.final_outliers;
		buildingS_plane_coefficients[i] = Ransac_buildings.final_model_coefficients;
		double inliers_percentage = static_cast<double>( (Ransac_buildings.n_best_inliers_count) ) / static_cast<double> (buildingS[i].rows());
		int inliers_so_far = Ransac_buildings.n_best_inliers_count;
		std::vector<int> old_final_outliers = Ransac_buildings.final_outliers;
		 

		// DRAWS THE ROOFS yellow
		for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++)
		{
			int pixel_row = static_cast<int>(buildingS[i](Ransac_buildings.final_inliers[k], 1) /  dem_spacing);
            int pixel_column = static_cast<int>(buildingS[i](Ransac_buildings.final_inliers[k], 0) /  dem_spacing);

			unsigned char r = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
            unsigned char g = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
            unsigned char b = 0;//unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
		
			roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b;
            roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g;
            roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r;
		}

		while (inliers_percentage < 0.90)
		{
			cont ++;
			Ransac_buildings.ransac_msg += "\nITERATION NUMBER " + StringUtilities::toDisplayString(cont) +"\n";
			Eigen::Matrix<double,  Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> building_outliers;
			building_outliers.setConstant(buildingS[i].rows() - inliers_so_far, 3, 0.0);
			
		   	//* forse il metodo va già bene così, perchè riempio la matrice deglio outlier in maniera ordinata,
			//* solo che gli indici degli inlier/outlier non sono più indicativi rispetto alla matrice di building originale, ma rispetto alla matrice di innput
			//* devo riporatre gli ID degli indici alla loro posizione originale
			for (int w = 0; w <building_outliers.rows(); w++)
			{
				building_outliers(w, 0) = buildingS[i](old_final_outliers[w], 0);
			    building_outliers(w, 1) = buildingS[i](old_final_outliers[w], 1);
			    building_outliers(w, 2) = buildingS[i](old_final_outliers[w], 2);
				
				//Ransac_buildings.ransac_msg += "\n" + StringUtilities::toDisplayString(pixel_row+1) + "\t" + StringUtilities::toDisplayString(pixel_column+1) + "\t" + StringUtilities::toDisplayString(final_outliers[w]) + "\t" + StringUtilities::toDisplayString(building_outliers(w, 0))+ "\t"+ StringUtilities::toDisplayString(building_outliers(w, 1)) + "\t" + StringUtilities::toDisplayString(building_outliers(w, 2))+"\n"; // needed for tesing (test passed at first iteration)
			}
			

			Ransac_buildings.ransac_msg += "\n";
			//Ransac_buildings.ransac_msg += "\nprova "+ StringUtilities::toDisplayString(inliers_percentage*100)+"\n";
			Ransac_buildings.ComputeModel(building_outliers, ransac_threshold);
			//inliers_percentage = inliers_percentage + static_cast<double>( (n_best_inliers_count) ) / static_cast<double> (building_outliers.rows());
			inliers_percentage = inliers_percentage + static_cast<double>( (Ransac_buildings.n_best_inliers_count) ) / static_cast<double> (buildingS[i].rows());

			Ransac_buildings.ransac_msg += "\nINLIERS IN RELATION TO GLOBAL INDEX ("+ StringUtilities::toDisplayString(Ransac_buildings.n_best_inliers_count) + ")\n";
	        for(size_t i = 0; i < Ransac_buildings.n_best_inliers_count; i++)
	        {
		       Ransac_buildings.ransac_msg +=  StringUtilities::toDisplayString(old_final_outliers[Ransac_buildings.final_inliers[i]])+" ";
			   inliers_file << old_final_outliers[Ransac_buildings.final_inliers[i]] << "\t";
	        }
			Ransac_buildings.ransac_msg += "\n";
			inliers_file << "\n";

			//old_final_outliers.resize(building_outliers.rows() - Ransac_buildings.n_best_inliers_count);
			Ransac_buildings.ransac_msg += "\nOUTLIERS IN RELATION TO GLOBAL INDEX("+ StringUtilities::toDisplayString(building_outliers.rows() - Ransac_buildings.n_best_inliers_count) + ")\n";
			for(size_t i = 0; i < building_outliers.rows() - Ransac_buildings.n_best_inliers_count; i++)
			{
				Ransac_buildings.ransac_msg +=  StringUtilities::toDisplayString(old_final_outliers[Ransac_buildings.final_outliers[i]])+" ";
				old_final_outliers[i] = old_final_outliers[Ransac_buildings.final_outliers[i]];// in this way I refer the outliers indexes to the global indexes (those referred to the original eigen matrix)
			}
			
			//parameters_file << Ransac_buildings.final_model_coefficients[0] << "\t" << Ransac_buildings.final_model_coefficients[1] << "\t" << Ransac_buildings.final_model_coefficients[2] << "\t" << Ransac_buildings.final_model_coefficients[3] << "\t" << Ransac_buildings.mean_distances << "\t"<< Ransac_buildings.std_distances << "\n";
			parameters_file << Ransac_buildings.final_model_coefficients[0] << "\t" << Ransac_buildings.final_model_coefficients[1] << "\t" << Ransac_buildings.final_model_coefficients[2] << "\t" << Ransac_buildings.final_model_coefficients[3] << "\n";


			if (cont == 1)
			{
				// DRAWS THE ROOFS blue
			   for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++)
			   {
					int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) /  dem_spacing);
					int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) /  dem_spacing);

					unsigned char r = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
					unsigned char g = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
					unsigned char b = 255;//unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
		
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b;
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g;
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r;
				}
			}

			if (cont ==2)
			{
				// DRAWS THE ROOFS green
			   for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++)
			   {
					int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) /  dem_spacing);
					int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) /  dem_spacing);

					unsigned char r = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
					unsigned char g = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
					unsigned char b = 0;//unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
		
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b;
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g;
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r;
				}
			}

			if (cont ==3)
			{
				// DRAWS THE ROOFS brown
			   for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++)
			   {
					int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) /  dem_spacing);
					int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) /  dem_spacing);

					unsigned char r = 128;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
					unsigned char g = 0;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
					unsigned char b = 0;//unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
		
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b;
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g;
					roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r;
				}
			}

			//if (cont == 4)
			//{
			//	// DRAWS THE ROOFS white
			//   for (int k = 0; k < Ransac_buildings.n_best_inliers_count; k++)
			//   {
			//		int pixel_row = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 1) /  dem_spacing);
			//		int pixel_column = static_cast<int>(buildingS[i](old_final_outliers[Ransac_buildings.final_inliers[k]], 0) /  dem_spacing);

			//		unsigned char r = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
			//		unsigned char g = 255;// unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
			//		unsigned char b = 255;//unsigned char(255 * (rand()/(1.0 + RAND_MAX)));
		
			//		roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[0] = b;
			//		roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[1] = g;
			//		roof_image.at<cv::Vec3b>(pixel_row, pixel_column)[2] = r;
			//	}
			//}


			Ransac_buildings.ransac_msg += "\n"; 
			inliers_so_far += Ransac_buildings.n_best_inliers_count;  
			
		    
		}// fine while
		Ransac_buildings.ransac_msg += "__________________________________________________________________\n";
		//boh_file.close();

		cont_file << i << "\t" << cont << "\n";
	}
	building_file.close();
	cont_file.close();
	cv::imshow("roofs", roof_image);
	
	cv::imwrite(path + "/Results/building_roofs.png", roof_image);
	cv::waitKey(0);
	
	pProgress->updateProgress("All buildings have been processed with RANSAC.", 100, NORMAL);
    pStep->finalize();
	return true;
}
bool Orthorectification::process(int type, RasterElement *pDSM, GRID DSMGrid, double Geoid_Offset, int DSM_resampling)
{
	StepResource pStep("Orthorectification Process", "app", "B4D426EC-E06D-11E1-83C8-42E56088709B");
	pStep->addStep("Start","app", "B4D426EC-E06D-11E1-83C8-42E56088709B");
	boxsize=0;

	res_type = type;

	if (res_type == 0) 
	{
		boxsize=0;	
	}
	else if (res_type == 1)
	{
		boxsize=1;		
	}
	else if (res_type == 2)
	{
		boxsize=2;		
	}
	else if (res_type == 3)
	{
		boxsize=3;	
	}

    ProgressResource pResource("ProgressBar");

	Progress *pProgress=pResource.get(); 

	pProgress->setSettingAutoClose(false);

	RasterDataDescriptor* pDesc = static_cast<RasterDataDescriptor*>(Image->getDataDescriptor());
    
    FactoryResource<DataRequest> pRequest;
    DataAccessor pSrcAcc = Image->getDataAccessor(pRequest.release());

    RasterDataDescriptor* pDescDSM = static_cast<RasterDataDescriptor*>(pDSM->getDataDescriptor());

	FactoryResource<DataRequest> pRequestDSM;
    DataAccessor pDSMAcc = pDSM->getDataAccessor(pRequestDSM.release());

 
	unsigned int N_Row = int(OrthoGrid.Y_Dim)+1;
	unsigned int N_Col = int(OrthoGrid.X_Dim)+1;

	// Check name of raster element //
	Service<ModelServices> pModel;
    vector<string> mCubeNames = pModel->getElementNames("RasterElement");

	int NameIndex = 0, control=0;
	stringstream out;
	string OutputName=Image->getName();
	string OutputName1 = OutputName.substr(0,OutputName.find_last_of("."));

	while (control == 0)
	{
		control = 1;
		OutputName = OutputName1+"_ortho_";

		out << NameIndex;
		OutputName.append(out.str()+".tiff");		
		
		for (unsigned int k=0; k<mCubeNames.size(); k++)
		{
		if (OutputName.compare(mCubeNames[k]) == 0) control = 0;
		}

		NameIndex++;
		out.str("");
		out.clear();

	}

	// Create output raster element and assoiciated descriptor and accessor //
	
	ModelResource<RasterElement> pResultCube(RasterUtilities::createRasterElement(OutputName,N_Row ,N_Col, FLT4BYTES));

	RasterDataDescriptor* pResultDesc = static_cast<RasterDataDescriptor*> (pResultCube->getDataDescriptor());

    FactoryResource<DataRequest> pResultRequest;
    pResultRequest->setWritable(true);
    DataAccessor pDestAcc = pResultCube->getDataAccessor(pResultRequest.release());

    double NodeLat, NodeLon, H_IJ=0;
	//int DSM_I, DSM_J;

    for (unsigned int row = 0; row < N_Row; ++row)
    {
	  if (pProgress != NULL)
	  {
      pProgress->updateProgress("Calculating result", row * 100 / N_Row, NORMAL);
	  }

      if (!pDestAcc.isValid())
      {
         std::string msg = "Unable to access the cube data.";
         pProgress->updateProgress(msg, 0, ERRORS);
		 pStep->finalize(Message::Failure, msg);
         return false;
      }

      for (unsigned int col = 0; col < N_Col; ++col)
      {

		  NodeLat = OrthoGrid.Lat_Min+row*OrthoGrid.Lat_Step;
		  NodeLon = OrthoGrid.Lon_Min+col*OrthoGrid.Lon_Step;

		  // RETRIEVE HEIGHT VALUE FROM DSM 

		  if (DSM_resampling == 0) 
		  {
		  int DSM_I = int((NodeLon - DSMGrid.Lon_Min)/DSMGrid.Lon_Step);
		  int DSM_J = pDescDSM->getRowCount() - int((NodeLat - DSMGrid.Lat_Min)/DSMGrid.Lat_Step);		  
          pDSMAcc->toPixel(DSM_J,DSM_I);
	      VERIFY(pDSMAcc.isValid());
          H_IJ = (pDSMAcc->getColumnAsDouble());
		  }
		  else
		  {
		  double DSM_I = ((NodeLon - DSMGrid.Lon_Min)/DSMGrid.Lon_Step);
		  double DSM_J = pDescDSM->getRowCount() - ((NodeLat - DSMGrid.Lat_Min)/DSMGrid.Lat_Step);
		  H_IJ = bilinear_height(pDSMAcc,DSM_I,DSM_J);
		  }

		  P_COORD NodeImage = Model->SAR_GroundToImage(NodeLon,NodeLat,H_IJ+Geoid_Offset);

		  if ((NodeImage.I>1 && NodeImage.I< Model->Metadata.Width-1) && (NodeImage.J>1 && NodeImage.J< Model->Metadata.Height-1))
		  {
			switchOnEncoding(pResultDesc->getDataType(), copypixel3, pDestAcc->getColumn(), pSrcAcc, int(NodeImage.I), int(NodeImage.J),boxsize, H_IJ);		
		  }		  
		  pDestAcc->nextColumn();
      }

      pDestAcc->nextRow();
    }

   Service<DesktopServices> pDesktop;

   Service<ModelServices> pMod;

   GcpList* GcpL = static_cast<GcpList*>(pMod->createElement("corner coordinate","GcpList",pResultCube.get()));
   
   // Update GCPs Information: to account for Opticks reading gcp lat&lon values the opposite way around, 
   // here it is necessary to switch the value to assign lat to gcp.mCoordinate.mX  and lon to gcp.mCoordinate.mY 

   GcpPoint Punto;

   Punto.mCoordinate.mX = OrthoGrid.Lat_Min;
   Punto.mCoordinate.mY = OrthoGrid.Lon_Min;
   Punto.mCoordinate.mZ = 0.0;
   Punto.mPixel.mX = 0.0;
   Punto.mPixel.mY = 0.0;

   GcpL->addPoint(Punto);

   Punto.mCoordinate.mX = OrthoGrid.Lat_Max;
   Punto.mCoordinate.mY = OrthoGrid.Lon_Min;
   Punto.mCoordinate.mZ = 0.0;
   Punto.mPixel.mX = 0.0;
   Punto.mPixel.mY = OrthoGrid.Y_Dim;
   
   GcpL->addPoint(Punto);

   Punto.mCoordinate.mX = OrthoGrid.Lat_Min;
   Punto.mCoordinate.mY = OrthoGrid.Lon_Max;
   Punto.mCoordinate.mZ = 0.0;
   Punto.mPixel.mX = OrthoGrid.X_Dim;
   Punto.mPixel.mY = 0.0;
   
   GcpL->addPoint(Punto);

   Punto.mCoordinate.mX = OrthoGrid.Lat_Max;
   Punto.mCoordinate.mY = OrthoGrid.Lon_Max;
   Punto.mCoordinate.mZ = 0.0;
   Punto.mPixel.mX = OrthoGrid.X_Dim;
   Punto.mPixel.mY = OrthoGrid.Y_Dim;
   
   GcpL->addPoint(Punto); 

   SpatialDataWindow* pWindow = static_cast<SpatialDataWindow*>(pDesktop->createWindow(pResultCube->getName(),
         SPATIAL_DATA_WINDOW));
 
   SpatialDataView* pView = (pWindow == NULL) ? NULL : pWindow->getSpatialDataView();  

   pView->setPrimaryRasterElement(pResultCube.get());

   pView->createLayer(RASTER, pResultCube.get());
   
   pView->createLayer(GCP_LAYER,GcpL,"GCP");

   pView->setDataOrigin(LOWER_LEFT);

   pResultCube.release();

   pProgress->updateProgress("Orthorectification is complete.", 100, NORMAL);
   pStep->addStep("End","app", "B4D426EC-E06D-11E1-83C8-42E56088709B");
   pStep->finalize();

   return true;
   
}