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; }
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; }