int _createmapniklayer(const std::string& sLayerName, const std::string& sLayerPath, const std::vector<double>& vecBoundary, boost::shared_ptr<Logger> qLogger) { if (!FileSystem::makedir(sLayerPath)) { qLogger->Error("Can't create directory " + sLayerPath); return ERROR_LAYERDIR; } boost::shared_ptr<PointLayerSettings> qPointLayerSettings = boost::shared_ptr<PointLayerSettings>(new PointLayerSettings()); if (!qPointLayerSettings) {return ERROR_OUTOFMEMORY;} qPointLayerSettings->SetLayerName(sLayerName); qPointLayerSettings->SetBoundary(vecBoundary[0], vecBoundary[1], vecBoundary[2], vecBoundary[3], vecBoundary[4], vecBoundary[5]); if (!qPointLayerSettings->Save(sLayerPath)) { qLogger->Error("Can't write into layer path: " + sLayerPath); return ERROR_WRITE_PERMISSION; } return 0; }
int _createimagelayer(const std::string& sLayerName, const std::string& sLayerPath, int nLod, const std::vector<int64>& vecExtent, boost::shared_ptr<Logger> qLogger, bool temp) { if (!FileSystem::makedir(sLayerPath)) { qLogger->Error("Can't create directory " + sLayerPath); return ERROR_LAYERDIR; } boost::shared_ptr<ImageLayerSettings> qImageLayerSettings = boost::shared_ptr<ImageLayerSettings>(new ImageLayerSettings()); if (!qImageLayerSettings) {return ERROR_OUTOFMEMORY;} qImageLayerSettings->SetLayerName(sLayerName); qImageLayerSettings->SetMaxLod(nLod); qImageLayerSettings->SetTileExtent(vecExtent[0], vecExtent[1], vecExtent[2], vecExtent[3]); if (!qImageLayerSettings->Save(sLayerPath)) { qLogger->Error("Can't write into layer path: " + sLayerPath); return ERROR_WRITE_PERMISSION; } return _createDirectoriesXY(sLayerPath, qLogger, vecExtent, nLod, temp); }
int process( boost::shared_ptr<Logger> qLogger, boost::shared_ptr<ProcessingSettings> qSettings, std::string sLayer, bool bVerbose, bool bLock, int epsg, std::string sImagefile, bool bFill, int& out_lod, int64& out_x0, int64& out_y0, int64& out_x1, int64& out_y1) { DataSetInfo oInfo; if (!ProcessingUtils::init_gdal()) { qLogger->Error("gdal-data directory not found!"); return ERROR_GDAL; } //--------------------------------------------------------------------------- // Retrieve ImageLayerSettings: std::ostringstream oss; std::string sImageLayerDir = FilenameUtils::DelimitPath(qSettings->GetPath()) + sLayer; std::string sTileDir = FilenameUtils::DelimitPath(FilenameUtils::DelimitPath(sImageLayerDir) + "tiles"); boost::shared_ptr<ImageLayerSettings> qImageLayerSettings = ImageLayerSettings::Load(sImageLayerDir); if (!qImageLayerSettings) { qLogger->Error("Failed retrieving image layer settings! Make sure to create it using 'createlayer'."); ProcessingUtils::exit_gdal(); return ERROR_IMAGELAYERSETTINGS; } int lod = qImageLayerSettings->GetMaxLod(); out_lod = lod; int64 layerTileX0, layerTileY0, layerTileX1, layerTileY1; qImageLayerSettings->GetTileExtent(layerTileX0, layerTileY0, layerTileX1, layerTileY1); if (bVerbose) { oss << "\nImage Layer:\n"; oss << " name = " << qImageLayerSettings->GetLayerName() << "\n"; oss << " maxlod = " << lod << "\n"; oss << " extent = " << layerTileX0 << ", " << layerTileY0 << ", " << layerTileX1 << ", " << layerTileY1 << "\n"; } //--------------------------------------------------------------------------- boost::shared_ptr<CoordinateTransformation> qCT; qCT = boost::shared_ptr<CoordinateTransformation>(new CoordinateTransformation(epsg, 3785)); clock_t t0,t1; t0 = clock(); ProcessingUtils::RetrieveDatasetInfo(sImagefile, qCT.get(), &oInfo, bVerbose); if (!oInfo.bGood) { qLogger->Error("Failed retrieving info!"); } if (bVerbose) { oss << "Loaded image info:\n Image Size: w= " << oInfo.nSizeX << ", h= " << oInfo.nSizeY << "\n"; oss << " dest: " << oInfo.dest_lrx << ", " << oInfo.dest_lry << ", " << oInfo.dest_ulx << ", " << oInfo.dest_uly << "\n"; qLogger->Info(oss.str()); oss.str(""); } boost::shared_ptr<MercatorQuadtree> qQuadtree = boost::shared_ptr<MercatorQuadtree>(new MercatorQuadtree()); int64 px0, py0, px1, py1; qQuadtree->MercatorToPixel(oInfo.dest_ulx, oInfo.dest_uly, lod, px0, py0); qQuadtree->MercatorToPixel(oInfo.dest_lrx, oInfo.dest_lry, lod, px1, py1); int64 imageTileX0, imageTileY0, imageTileX1, imageTileY1; qQuadtree->PixelToTileCoord(px0, py0, imageTileX0, imageTileY0); qQuadtree->PixelToTileCoord(px1, py1, imageTileX1, imageTileY1); if (bVerbose) { oss << "\nTile Coords (image):"; oss << " (" << imageTileX0 << ", " << imageTileY0 << ")-(" << imageTileX1 << ", " << imageTileY1 << ")\n"; qLogger->Info(oss.str()); oss.str(""); } // check if image is outside layer if (imageTileX0 > layerTileX1 || imageTileY0 > layerTileY1 || imageTileX1 < layerTileX0 || imageTileY1 < layerTileY0) { qLogger->Info("The dataset is outside of the layer and not being added!"); ProcessingUtils::exit_gdal(); return 0; } // clip tiles to layer extent imageTileX0 = math::Max<int64>(imageTileX0, layerTileX0); imageTileY0 = math::Max<int64>(imageTileY0, layerTileY0); imageTileX1 = math::Min<int64>(imageTileX1, layerTileX1); imageTileY1 = math::Min<int64>(imageTileY1, layerTileY1); out_x0 = imageTileX0; out_y0 = imageTileY0; out_x1 = imageTileX1; out_y1 = imageTileY1; // Load image boost::shared_array<unsigned char> vImage = ProcessingUtils::ImageToMemoryRGB(oInfo); unsigned char* pImage = vImage.get(); if (!vImage) { qLogger->Error("Can't load image into memory!\n"); return ERROR_NOMEMORY; } //######################################################################## // Beacuse proj4 is not thread safe at this time, // the target extents are precalculate. // unfortunately this can't be fixed by using OpenMP locks / critical sections int64 numTiles = (imageTileX1-imageTileX0+1)*(imageTileY1-imageTileY0+1); boost::shared_array<Anchor> vAnchor = boost::shared_array<Anchor>(new Anchor[numTiles]); Anchor* pAnchor = vAnchor.get(); if (!vAnchor) { qLogger->Error("Not enough memory for target tile structure! (This is a known issue and will be fixed soon!)\n"); return ERROR_NOMEMORY; } if (bVerbose) { oss << "\nCalculating Destination Coordinates (transformation)..."; qLogger->Info(oss.str()); oss.str(""); } for (int64 xx = imageTileX0; xx <= imageTileX1; ++xx) { for (int64 yy = imageTileY0; yy <= imageTileY1; ++yy) { int64 cnt = (xx-imageTileX0)*(imageTileY1-imageTileY0+1)+yy-imageTileY0; std::string sQuadcode = qQuadtree->TileCoordToQuadkey(xx,yy,lod); double px0m, py0m, px1m, py1m; qQuadtree->QuadKeyToMercatorCoord(sQuadcode, px0m, py0m, px1m, py1m); double ulx = px0m; double uly = py1m; double lrx = px1m; double lry = py0m; double anchor_Ax = ulx; double anchor_Ay = lry; double anchor_Bx = lrx; double anchor_By = lry; double anchor_Cx = lrx; double anchor_Cy = uly; double anchor_Dx = ulx; double anchor_Dy = uly; qCT->TransformBackwards(&anchor_Ax, &anchor_Ay); qCT->TransformBackwards(&anchor_Bx, &anchor_By); qCT->TransformBackwards(&anchor_Cx, &anchor_Cy); qCT->TransformBackwards(&anchor_Dx, &anchor_Dy); pAnchor[cnt].anchor_Ax = anchor_Ax; pAnchor[cnt].anchor_Ay = anchor_Ay; pAnchor[cnt].anchor_Bx = anchor_Bx; pAnchor[cnt].anchor_By = anchor_By; pAnchor[cnt].anchor_Cx = anchor_Cx; pAnchor[cnt].anchor_Cy = anchor_Cy; pAnchor[cnt].anchor_Dx = anchor_Dx; pAnchor[cnt].anchor_Dy = anchor_Dy; cnt++; } } //######################################################################## if (bVerbose) { oss << "\nCalculating Tiles"; qLogger->Info(oss.str()); oss.str(""); } // iterate through all tiles and create them #pragma omp parallel for for (int64 xx = imageTileX0; xx <= imageTileX1; ++xx) { for (int64 yy = imageTileY0; yy <= imageTileY1; ++yy) { int64 cnt = (xx-imageTileX0)*(imageTileY1-imageTileY0+1)+yy-imageTileY0; boost::shared_array<unsigned char> vTile; std::string sQuadcode = qQuadtree->TileCoordToQuadkey(xx,yy,lod); std::string sTilefile = ProcessingUtils::GetTilePath(sTileDir, ".png" , lod, xx, yy); if (bVerbose) { std::stringstream sst; sst << "processing " << sQuadcode << " (" << xx << ", " << yy << ")"; qLogger->Info(sst.str()); } //--------------------------------------------------------------------- // LOCK this tile. If this tile is currently locked // -> wait until lock is removed. int lockhandle = -1; if (bLock) { lockhandle = FileSystem::Lock(sTilefile); } else { std::cout << "WARNING: locking disabled\n"; } //--------------------------------------------------------------------- // if mode is --fill: (bFill) // * load possibly existing tile into vTile // ... * if there is none, clear vTile (memset 0) // if mode is --overwrite (bOverwrite) // * load possibly existing tile into vTile // * if there is none, clear vTile (memset 0) // * overwrite //_-------------------------------------------------------------------- // load tile: // tile already exists ? bool bCreateNew = true; if (FileSystem::FileExists(sTilefile)) { qLogger->Info(sTilefile + " already exists, updating"); ImageObject outputimage; if (ImageLoader::LoadFromDisk(Img::Format_PNG, sTilefile, Img::PixelFormat_RGBA, outputimage)) { if (outputimage.GetHeight() == tilesize && outputimage.GetWidth() == tilesize) { vTile = outputimage.GetRawData(); bCreateNew = false; } } } if (bCreateNew) { // create new tile memory and clear to fully transparent vTile = boost::shared_array<unsigned char>(new unsigned char[tilesize*tilesize*4]); memset(vTile.get(),0,tilesize*tilesize*4); } unsigned char* pTile = vTile.get(); // Copy image to tile: /*double px0m, py0m, px1m, py1m; qQuadtree->QuadKeyToMercatorCoord(sQuadcode, px0m, py0m, px1m, py1m); double ulx = px0m; double uly = py1m; double lrx = px1m; double lry = py0m; double anchor_Ax = ulx; double anchor_Ay = lry; double anchor_Bx = lrx; double anchor_By = lry; double anchor_Cx = lrx; double anchor_Cy = uly; double anchor_Dx = ulx; double anchor_Dy = uly; // avoid calculating transformation per pixel. This is done using anchor point method qCT->TransformBackwards(&anchor_Ax, &anchor_Ay); qCT->TransformBackwards(&anchor_Bx, &anchor_By); qCT->TransformBackwards(&anchor_Cx, &anchor_Cy); qCT->TransformBackwards(&anchor_Dx, &anchor_Dy); */ double anchor_Ax = pAnchor[cnt].anchor_Ax; double anchor_Ay = pAnchor[cnt].anchor_Ay; double anchor_Bx = pAnchor[cnt].anchor_Bx; double anchor_By = pAnchor[cnt].anchor_By; double anchor_Cx = pAnchor[cnt].anchor_Cx; double anchor_Cy = pAnchor[cnt].anchor_Cy; double anchor_Dx = pAnchor[cnt].anchor_Dx; double anchor_Dy = pAnchor[cnt].anchor_Dy; // write current tile for (int ty=0;ty<tilesize;++ty) { for (int tx=0;tx<tilesize;++tx) { double dx = (double)tx*dWanc; double dy = (double)ty*dHanc; double xd = (anchor_Ax*(1.0-dx)*(1.0-dy)+anchor_Bx*dx*(1.0-dy)+anchor_Dx*(1.0-dx)*dy+anchor_Cx*dx*dy); double yd = (anchor_Ay*(1.0-dx)*(1.0-dy)+anchor_By*dx*(1.0-dy)+anchor_Dy*(1.0-dx)*dy+anchor_Cy*dx*dy); // pixel coordinate in original image double dPixelX = (oInfo.affineTransformation_inverse[0] + xd * oInfo.affineTransformation_inverse[1] + yd * oInfo.affineTransformation_inverse[2]); double dPixelY = (oInfo.affineTransformation_inverse[3] + xd * oInfo.affineTransformation_inverse[4] + yd * oInfo.affineTransformation_inverse[5]); unsigned char r,g,b,a; // out of image -> set transparent if (dPixelX<0 || dPixelX>oInfo.nSizeX || dPixelY<0 || dPixelY>oInfo.nSizeY) { r = g = b = a = 0; } else { // read pixel in image pImage[dPixelX, dPixelY] (biliear, bicubic or nearest neighbour) // and store as r,g,b _ReadImageValueBilinear(pImage, oInfo.nSizeX, oInfo.nSizeY, dPixelX, dPixelY, &r, &g, &b, &a); } size_t adr=4*ty*tilesize+4*tx; if (a>0) { if (bFill) { if (pTile[adr+3] == 0) { pTile[adr+0] = r; pTile[adr+1] = g; pTile[adr+2] = b; pTile[adr+3] = a; } } else // if (bOverwrite) { // currently RGB for testing purposes! pTile[adr+0] = r; pTile[adr+1] = g; pTile[adr+2] = b; pTile[adr+3] = a; } } } } // save tile (pTile) if (bVerbose) { qLogger->Info("Storing tile: " + sTilefile); } ImageWriter::WritePNG(sTilefile, pTile, tilesize, tilesize); // unlock file. Other computers/processes/threads can access it again. FileSystem::Unlock(sTilefile, lockhandle); } } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- t1=clock(); std::ostringstream out; out << "calculated in: " << double(t1-t0)/double(CLOCKS_PER_SEC) << " s \n"; qLogger->Info(out.str()); ProcessingUtils::exit_gdal(); return 0; }
int _start(int argc, char *argv[], boost::shared_ptr<Logger> qLogger, const std::string& processpath) { bool bError = false; po::options_description desc("Program-Options"); desc.add_options() ("name", po::value<std::string>(), "layer name (string)") ("lod", po::value<int>(), "desired level of detail (integer)") ("extent", po::value< std::vector<int64> >()->multitoken(), "tile boundary (tx0 ty0 tx1 ty1) for elevation/image data") ("boundary", po::value<std::vector<double> >()->multitoken(), "WGS84 boundary for point data or mapnik rendering") ("force", "[optional] force creation. (Warning: if this layer already exists it will be deleted)") ("numthreads", po::value<int>(), "[optional] force number of threads") ("type", po::value<std::string>(), "[optional] layer type. This can be image, elevation, poi, point, geometry. image is default value.") ; po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); } catch (std::exception&) { bError = true; } std::string sLayerName; int nLod = 0; std::vector<int64> vecExtent; std::vector<double> vecBoundary; bool bForce = false; ELayerType eLayer = IMAGE_LAYER; if (!vm.count("name")) { qLogger->Error("layer name is not specified!"); bError = true; } else { sLayerName = vm["name"].as<std::string>(); if (sLayerName.length() == 0) { qLogger->Error("layer name is empty!"); bError = true; } } if (!vm.count("lod")) { if(vm["type"].as< std::string >() != "mapnik") { qLogger->Error("lod not specified!"); bError = true; } } else { nLod = vm["lod"].as<int>(); } if (vm.count("force")) { bForce = true; } if (vm.count("extent")) { vecExtent = vm["extent"].as< std::vector<int64> >(); } if (vm.count("boundary")) { vecBoundary = vm["boundary"].as< std::vector<double> >(); } if (vm.count("numthreads")) { int n = vm["numthreads"].as<int>(); if (n>0 && n<65) { std::ostringstream oss; oss << "Forcing number of threads to " << n; qLogger->Info(oss.str()); omp_set_num_threads(n); } } if (vm.count("type")) { std::string sLayerType = vm["type"].as< std::string >(); if (sLayerType == "image") { eLayer = IMAGE_LAYER; } else if (sLayerType == "imagepostprocessing") { eLayer = IMAGE_POSTPROCESSING_LAYER; } else if (sLayerType == "mapnik") { eLayer = MAPNIK_LAYER; } else if (sLayerType == "elevation") { eLayer = ELEVATION_LAYER; } else if (sLayerType == "poi") { eLayer = POI_LAYER; } else if (sLayerType == "point") { eLayer = POINT_LAYER; } else if (sLayerType == "geometry") { eLayer = GEOMETRY_LAYER; } else { bError = true; } } else { qLogger->Warn("It is highly recommended to use --type! Using default --type image"); } if (eLayer == POINT_LAYER) { if (vecBoundary.size() != 6 ) { qLogger->Error("boundary must be specified with 6 values (WGS84): lng0 lat0 elv0 lng1 lat1 elv1"); bError = true; } } else { if (vecExtent.size() != 4 ) { qLogger->Error("extent must be defined with 4 values (Tile Coords): x0 y0 x1 y1"); bError = true; } } if (bError) { qLogger->Error("Wrong parameters!"); std::ostringstream sstr; sstr << desc; qLogger->Info("\n" + sstr.str()); return ERROR_PARAMS; } std::string sLayerPath = FilenameUtils::DelimitPath(processpath) + sLayerName; qLogger->Info("Target directory: " + sLayerPath); if (FileSystem::DirExists(sLayerPath)) { if (!bForce) { qLogger->Error("Layer already exists!!"); qLogger->Error("the directory " + sLayerPath + " already exists. Please delete manually or choose another layer name or use the --force option"); return ERROR_LAYEREXISTS; } else { qLogger->Info("Force option detected. Deleting already existing layer... this may take a while"); if (!FileSystem::rm_all(sLayerPath)) { qLogger->Error("Can't delete old layer (file permission)."); return ERROR_DELETE_PERMISSION; } else { qLogger->Info("ok.. layer deleted."); } } } if (eLayer == IMAGE_LAYER) { return _createimagelayer(sLayerName, sLayerPath, nLod, vecExtent, qLogger, false); } if (eLayer == IMAGE_POSTPROCESSING_LAYER) { return _createimagelayer(sLayerName, sLayerPath, nLod, vecExtent, qLogger, true); } if (eLayer == MAPNIK_LAYER) { return _createmapniklayer(sLayerName, sLayerPath, vecBoundary, qLogger); } else if (eLayer == ELEVATION_LAYER) { return _createelevationlayer(sLayerName, sLayerPath, nLod, vecExtent, qLogger); } else if (eLayer == POINT_LAYER) { return _createpointlayer(sLayerName, sLayerPath, nLod, vecBoundary, qLogger); } else { return ERROR_UNSUPPORTED; } }
int process( boost::shared_ptr<Logger> qLogger, boost::shared_ptr<ProcessingSettings> qSettings, std::string sLayer, bool bVerbose, bool bLock, int epsg, std::string sPointFile, bool bFill, int& out_lod, int64& out_x0, int64& out_y0, int64& out_z0, int64& out_x1, int64& out_y1, int64& out_z1) { clock_t t0,t1; t0 = clock(); if (!ProcessingUtils::init_gdal()) { qLogger->Error("gdal-data directory not found!"); return ERROR_GDAL; } boost::shared_ptr<CoordinateTransformation> qCT; qCT = boost::shared_ptr<CoordinateTransformation>(new CoordinateTransformation(epsg, 4326)); //--------------------------------------------------------------------------- // Retrieve PointLayerSettings: std::ostringstream oss; std::string sPointLayerDir = FilenameUtils::DelimitPath(qSettings->GetPath()) + sLayer; std::string sTileDir = FilenameUtils::DelimitPath(FilenameUtils::DelimitPath(sPointLayerDir) + "tiles"); std::string sTempDir = FilenameUtils::DelimitPath(FilenameUtils::DelimitPath(sPointLayerDir) + "temp/tiles"); std::string sIndexFile = FilenameUtils::DelimitPath(sPointLayerDir) + "temp/" + FilenameUtils::ExtractBaseFileName(sPointFile) + ".idx"; boost::shared_ptr<PointLayerSettings> qPointLayerSettings = PointLayerSettings::Load(sPointLayerDir); if (!qPointLayerSettings) { qLogger->Error("Failed retrieving point layer settings! Make sure to create it using 'createlayer'."); ProcessingUtils::exit_gdal(); return ERROR_ELVLAYERSETTINGS; } int lod = qPointLayerSettings->GetMaxLod(); double x0, y0, z0, x1, y1, z1; qPointLayerSettings->GetBoundary(x0, y0, z0, x1, y1, z1); if (bVerbose) { oss << "Point Layer:\n"; oss << " name = " << qPointLayerSettings->GetLayerName() << "\n"; oss << " maxlod = " << lod << "\n"; oss << " boundary = (" << x0 << ", " << y0 << ", " << z0 << ")-(" << x1 << ", " << y1 << ", " << z1 << ")\n"; qLogger->Info(oss.str()); oss.str(""); } double lodlen = pow(2.0,lod); //------------------------------------------------------------------------ // Calculate matrix for octree voxel data transformation double xcenter, ycenter, zcenter; xcenter = x0 + fabs(x1-x0)*0.5; ycenter = y0 + fabs(y1-y0)*0.5; zcenter = z0 + fabs(z1-z0)*0.5; // elevation is currently ignored and set to 0 double len = OCTREE_CUBE_SIZE; // octree cube size mat4<double> L, Linv; // center to radiant double lng = DEG2RAD(xcenter); double lat = DEG2RAD(ycenter); // center to cartesian coord vec3<double> vCenter; GeoCoord geoCenter(xcenter, ycenter, zcenter); geoCenter.GetCartesian(vCenter); // create orthonormal basis // (and create 4x4 matrix with translation to vCenter) // scale to normalized geozentric cartesian coordinates (scaled meters) double scalelen = CARTESIAN_SCALE_INV * len; // translate to center (lng,lat) mat4<double> matTrans; matTrans.SetTranslation(vCenter); mat4<double> matNavigation; //matNavigation.CalcNavigationFrame(lng, lat); // Navigation frame with z-axis up! matNavigation.Set( -sin(lng), -sin(lat)*cos(lng), cos(lat)*cos(lng), 0, cos(lng), -sin(lat)*sin(lng), cos(lat)*sin(lng), 0, 0, cos(lat), sin(lat), 0, 0, 0, 0, 1); // scale to range [-0.5,0.5] (local coordinates) mat4<double> matScale; matScale.SetScale(scalelen); // translate to range [0,1] mat4<double> matTrans2; matTrans2.SetTranslation(-0.5, -0.5, -0.5); L = matTrans; // translate to vCenter L *= matNavigation; // rotate to align ellipsoid normal L *= matScale; // scale to [-0.5, 0.5] L *= matTrans2; // translate [0.5, 0.5, 0.5] to have range [0,1] Linv = L.Inverse(); // create inverse of this transformation //------------------------------------------------------------------------ size_t numpts = 0; size_t totalpoints = 0; CloudPoint pt; CloudPoint pt_octree; // point in octree coords PointCloudReader pr; PointMap pointmap(lod); if (pr.Open(sPointFile)) { GeoCoord in_geopt; vec3<double> in_pt_cart; // point in geocentric cartesian coordinates (WGS84) vec3<double> out_pt_octree; // point in local octree coordinates while (pr.ReadPoint(pt)) { qCT->Transform(&pt.x, &pt.y); in_geopt.SetLongitude(pt.x); in_geopt.SetLatitude(pt.y); in_geopt.SetEllipsoidHeight(pt.elevation); in_geopt.ToCartesian(&in_pt_cart.x, &in_pt_cart.y, &in_pt_cart.z); out_pt_octree = Linv.vec3mul(in_pt_cart); pt_octree.r = pt.r; pt_octree.g = pt.g; pt_octree.b = pt.b; pt_octree.a = pt.a; pt_octree.intensity = pt.intensity; pt_octree.x = out_pt_octree.x; pt_octree.y = out_pt_octree.y; pt_octree.elevation = out_pt_octree.z; int64 octreeX = int64(out_pt_octree.x * lodlen); int64 octreeY = int64(out_pt_octree.y * lodlen); int64 octreeZ = int64(out_pt_octree.z * lodlen); // now we have the octree coordinate (octreeX,Y,Z) of the point // -> add the point to pointmap (which is actually a hash map) // -> note: don't calculate the octocode for each point, it would be way too slow. pointmap.AddPoint(octreeX, octreeY, octreeZ, pt_octree); if (pointmap.GetNumPoints()>membuffer) { totalpoints+=pointmap.GetNumPoints(); pointmap.ExportData(sTempDir); pointmap.Clear(); } numpts++; } } else { return -1; } if (pointmap.GetNumPoints()>0) pointmap.ExportData(sTempDir); totalpoints+=pointmap.GetNumPoints(); // export list of all written tiles (for future processing) if (bVerbose) { oss << "Exporting index...\n"; qLogger->Info(oss.str()); oss.str(""); } pointmap.ExportIndex(sIndexFile); //------------------------------------------------------------------------ ProcessingUtils::exit_gdal(); std::cout << "Pointmap Stats:\n"; std::cout << " numpoints: " << totalpoints << "\n"; t1 = clock(); std::cout << "calculated in: " << double(t1-t0)/double(CLOCKS_PER_SEC) << " s \n"; return 0; }