bool vtBuilding::GetBaseLevelCenter(DPoint2 &p) const { DRECT rect; if (!GetExtents(rect)) return false; rect.GetCenter(p); return true; }
void vtUtilityMap::GetPoleExtents(DRECT &rect) { if (m_Poles.IsEmpty()) return; rect.SetRect(1E9, -1E9, -1E9, 1E9); int i, size = m_Poles.GetSize(); for (i = 0; i < size; i++) { vtPole *pole = m_Poles.GetAt(i); rect.GrowToContainPoint(pole->m_p); } }
void vtUtilityMap::GetPoleExtents(DRECT &rect) { if (m_Poles.empty()) return; rect.SetInsideOut(); const int size = m_Poles.size(); for (int i = 0; i < size; i++) { vtPole *pole = m_Poles[i]; rect.GrowToContainPoint(pole->m_p); } }
/** * If you are going to do a large number of height-testing of this TIN * (with FindAltitudeOnEarth), call this method once first to set up a * series of indexing bins which greatly speed up testing. * * \param bins Number of bins per dimension, e.g. a value of 50 produces * 50*50=2500 bins. More bins produces faster height-testing with * the only tradeoff being a small amount of RAM per bin. * \param progress_callback If supplied, this function will be called back * with a value of 0 to 100 as the operation progresses. */ void vtTin::SetupTriangleBins(int bins, bool progress_callback(int)) { DRECT rect = m_EarthExtents; m_BinSize.x = rect.Width() / bins; m_BinSize.y = rect.Height() / bins; delete m_trianglebins; m_trianglebins = new BinArray(bins, bins); uint tris = NumTris(); for (uint i = 0; i < tris; i++) { if ((i%100)==0 && progress_callback) progress_callback(i * 100 / tris); // get 2D points const DPoint2 &p1 = m_vert[m_tri[i*3]]; const DPoint2 &p2 = m_vert[m_tri[i*3+1]]; const DPoint2 &p3 = m_vert[m_tri[i*3+2]]; // find the correct range of bins, and add the index of this index to it DPoint2 fminrange, fmaxrange; fminrange.x = std::min(std::min(p1.x, p2.x), p3.x); fmaxrange.x = std::max(std::max(p1.x, p2.x), p3.x); fminrange.y = std::min(std::min(p1.y, p2.y), p3.y); fmaxrange.y = std::max(std::max(p1.y, p2.y), p3.y); IPoint2 bin_start, bin_end; bin_start.x = (uint) ((fminrange.x-rect.left) / m_BinSize.x); bin_end.x = (uint) ((fmaxrange.x-rect.left) / m_BinSize.x); bin_start.y = (uint) ((fminrange.y-rect.bottom) / m_BinSize.y); bin_end.y = (uint) ((fmaxrange.y-rect.bottom) / m_BinSize.y); for (int j = bin_start.x; j <= bin_end.x; j++) { for (int k = bin_start.y; k <= bin_end.y; k++) { Bin *bin = m_trianglebins->GetBin(j, k); if (bin) bin->push_back(i); } } } }
void vtStructureArray::GetExtents(DRECT &rect) const { if (GetSize() == 0) return; rect.SetRect(1E9, -1E9, -1E9, 1E9); DRECT rect2; int i, size = GetSize(); for (i = 0; i < size; i++) { vtStructure *str = GetAt(i); if (str->GetExtents(rect2)) rect.GrowToContainRect(rect2); } }
bool vtBuilding::IsContainedBy(const DRECT &rect) const { // I find that it's easier to select building using their centers // DRECT r; // GetExtents(r); // return rect.ContainsRect(r); DPoint2 center; GetBaseLevelCenter(center); return rect.ContainsPoint(center); }
// // Get an extent rectangle around the building. // It doesn't need to be exact. // bool vtBuilding::GetExtents(DRECT &rect) const { uint i, j; uint levs = m_Levels.GetSize(); if (levs == 0) return false; rect.SetRect(1E9, -1E9, -1E9, 1E9); for (i = 0; i < levs; i++) { vtLevel *lev = m_Levels[i]; if (lev->GetFootprint().size() != 0) // safety check { const DLine2 &outer = lev->GetOuterFootprint(); for (j = 0; j < outer.GetSize(); j++) rect.GrowToContainPoint(outer[j]); } } return true; }
void EnviroFrame::OnChar(wxKeyEvent& event) { static NavType prev = NT_Normal; vtTerrain *pTerr = g_App.GetCurrentTerrain(); long key = event.GetKeyCode(); // Keyboard shortcuts ("accelerators") switch (key) { case 27: // Esc: cancel a building or linear we're making if (g_App.m_mode == MM_BUILDINGS && g_App.IsMakingElastic()) g_App.CancelElastic(); else if (g_App.m_mode == MM_LINEARS && g_App.IsMakingElastic()) g_App.CancelElastic(); else // or exit the application { // It's not safe to close immediately, as that will kill the canvas, // and it might some Canvas event that caused us to close. So, // simply stop rendering, and delay closing until the next Idle event. m_canvas->m_bRunning = false; m_bCloseOnIdle = true; } break; case ' ': if (g_App.m_state == AS_Terrain) ToggleNavigate(); break; case 'f': ChangeFlightSpeed(1.8f); break; case 's': ChangeFlightSpeed(1.0f / 1.8f); break; case 'a': g_App.SetMaintain(!g_App.GetMaintain()); break; case '+': SetTerrainDetail(GetTerrainDetail()+1000); break; case '-': SetTerrainDetail(GetTerrainDetail()-1000); break; case 'd': // Toggle grab-pivot if (g_App.m_nav == NT_Grab) g_App.SetNavType(prev); else { prev = g_App.m_nav; g_App.SetNavType(NT_Grab); } break; case 'w': m_bAlwaysMove = !m_bAlwaysMove; if (g_App.m_pTFlyer != NULL) g_App.m_pTFlyer->SetAlwaysMove(m_bAlwaysMove); break; case '[': { float exag = pTerr->GetVerticalExag(); exag /= 1.01; pTerr->SetVerticalExag(exag); } break; case ']': { float exag = pTerr->GetVerticalExag(); exag *= 1.01; pTerr->SetVerticalExag(exag); } break; case 'e': m_bEarthLines = !m_bEarthLines; g_App.ShowEarthLines(m_bEarthLines); break; case 'y': // Example code: modify the terrain by using the (slow) approach of using // vtTerrain methods GetInitialGrid and UpdateElevation. { vtTerrain *pTerr = g_App.GetCurrentTerrain(); if (pTerr && pTerr->GetParams().GetValueBool(STR_ALLOW_GRID_SCULPTING)) { vtElevationGrid *grid = pTerr->GetInitialGrid(); if (grid) { clock_t t1 = clock(); // Raise an area of the terrain int cols, rows; grid->GetDimensions(cols, rows); for (int i = cols / 4; i < cols / 2; i++) for (int j = rows / 4; j < rows / 2; j++) { grid->SetFValue(i, j, grid->GetFValue(i, j) + 40); } pTerr->UpdateElevation(); clock_t t2 = clock(); VTLOG(" Modify1: %.3f sec\n", (float)(t2-t1)/CLOCKS_PER_SEC); // Update the shading and culture pTerr->ReshadeTexture(vtGetTS()->GetSunLightTransform()); DRECT area; area.SetToZero(); pTerr->RedrapeCulture(area); } } } break; case 'Y': // Example code: modify the terrain by using the (fast) approach of using // vtDynTerrainGeom::SetElevation. { vtTerrain *pTerr = g_App.GetCurrentTerrain(); if (pTerr) { vtDynTerrainGeom *dyn = pTerr->GetDynTerrain(); if (dyn) { clock_t t1 = clock(); // Raise an area of the terrain int cols, rows; dyn->GetDimensions(cols, rows); for (int i = cols / 4; i < cols / 2; i++) for (int j = rows / 4; j < rows / 2; j++) { dyn->SetElevation(i, j, dyn->GetElevation(i, j) + 40); } clock_t t2 = clock(); VTLOG(" Modify2: %.3f sec\n", (float)(t2-t1)/CLOCKS_PER_SEC); // Update the shading and culture pTerr->ReshadeTexture(vtGetTS()->GetSunLightTransform()); DRECT area; area.SetToZero(); pTerr->RedrapeCulture(area); } } } break; case 'u': // Example code: modify a small area of terrain around the mouse pointer. { vtTerrain *pTerr = g_App.GetCurrentTerrain(); if (pTerr) { vtDynTerrainGeom *dyn = pTerr->GetDynTerrain(); if (dyn) { // Get 3D cursor location in grid coordinates FPoint3 fpos; g_App.m_pTerrainPicker->GetCurrentPoint(fpos); IPoint2 ipos; dyn->WorldToGrid(fpos, ipos); for (int x = -4; x < 4; x++) for (int y = -4; y < 4; y++) { float val = dyn->GetElevation(ipos.x + x, ipos.y + y); dyn->SetElevation(ipos.x + x, ipos.y + y, val + 40); } // Update the (entire) shading and culture pTerr->ReshadeTexture(vtGetTS()->GetSunLightTransform()); DRECT area; area.SetToZero(); pTerr->RedrapeCulture(area); } } } break; case 'D': // Shift-D // dump camera info g_App.DumpCameraInfo(); break; case 2: // Ctrl-B // toggle demo g_App.ToggleDemo(); break; case WXK_F11: DoTestCode(); break; case WXK_F12: m_pSceneGraphDlg->Show(true); break; case WXK_DELETE: DeleteAllSelected(); break; default: event.Skip(); break; } }
void EnviroFrame::CarveTerrainToFitNode(osg::Node *node) { vtTerrain *terr = g_App.GetCurrentTerrain(); if (!terr) return; vtDynTerrainGeom *dyn = terr->GetDynTerrain(); if (!dyn) return; FSphere sph; GetBoundSphere(node, sph, true); int changed = 0; int cols, rows; dyn->GetDimensions(cols, rows); const FPoint3 yvec(0,100,0); for (int c = 0; c < cols; c++) { for (int r = 0; r < rows; r++) { FPoint3 wpos; dyn->GetWorldLocation(c, r, wpos); if (wpos.x < (sph.center.x - sph.radius)) continue; if (wpos.x > (sph.center.x + sph.radius)) continue; if (wpos.z < (sph.center.z - sph.radius)) continue; if (wpos.z > (sph.center.z + sph.radius)) continue; // Shoot a ray upwards through the terrain surface point vtHitList HitList; int iNumHits = vtIntersect(node, wpos - yvec, wpos + yvec, HitList); if (iNumHits) { FPoint3 pos = HitList.front().point; dyn->SetElevation(c, r, pos.y); changed++; } } } if (changed != 0) { wxString msg; msg.Printf(_T("Adjusted %d heixels. Re-shade the terrain?"), changed); int res = wxMessageBox(msg, _T(""), wxYES_NO, this); if (res == wxYES) { // Update the (entire) shading and culture EnableContinuousRendering(false); OpenProgressDialog(_("Recalculating Shading"), _T(""), false, this); terr->ReshadeTexture(vtGetTS()->GetSunLightTransform(), progress_callback); DRECT area; area.SetToZero(); terr->RedrapeCulture(area); CloseProgressDialog(); EnableContinuousRendering(true); } } }
bool vtElevLayer::ImportFromFile(const wxString &strFileName, bool progress_callback(int), vtElevError *err) { // Avoid trouble with '.' and ',' in Europe - all the file readers assume // the default "C" locale. ScopedLocale normal_numbers(LC_NUMERIC, "C"); wxString strExt = strFileName.AfterLast('.'); vtString fname = (const char *) strFileName.mb_str(wxConvUTF8); VTLOG("ImportFromFile '%s'\n", (const char *) fname); if (!strExt.CmpNoCase(_T("gz"))) { // ignore .gz, look at extension under it wxString dropped = strFileName.Left(strFileName.Len()-3); strExt = dropped.AfterLast('.'); } if (!strExt.CmpNoCase(_T("bz2"))) { // ignore .bz2, look at extension under it wxString dropped = strFileName.Left(strFileName.Len()-4); strExt = dropped.AfterLast('.'); } // The first character in the file is useful for telling which format // the file really is. FILE *fp = vtFileOpen(fname, "rb"); char first = fgetc(fp); fclose(fp); bool success = false; if (!strExt.CmpNoCase(_T("dxf"))) { m_pTin = new vtTin2d; success = m_pTin->ReadDXF(fname, progress_callback); } else if (!strFileName.Right(6).CmpNoCase(_T("xy.adf"))) { m_pTin = new vtTin2d; success = m_pTin->ReadADF(fname, progress_callback); } else if (!strFileName.Right(4).CmpNoCase(_T(".tin"))) { m_pTin = new vtTin2d; success = m_pTin->ReadGMS(fname, progress_callback); } else if (!strFileName.Right(4).CmpNoCase(_T(".ply"))) { m_pTin = new vtTin2d; success = m_pTin->ReadPLY(fname, progress_callback); } else { if (m_pGrid == NULL) m_pGrid = new vtElevationGrid; } if (!strExt.CmpNoCase(_T("3tx"))) { success = m_pGrid->LoadFrom3TX(fname, progress_callback); } else if (!strExt.CmpNoCase(_T("dem"))) { // If there is a .hdr file in the same place, it is most likely // a GTOPO30/SRTM30 file vtString hdr_fname = ChangeFileExtension(fname, ".hdr"); if (vtFileExists(hdr_fname)) success = m_pGrid->LoadFromGTOPO30(hdr_fname, progress_callback); else { if (first == '*') success = m_pGrid->LoadFromMicroDEM(fname, progress_callback); else success = m_pGrid->LoadFromDEM(fname, progress_callback, err); } } else if (!strExt.CmpNoCase(_T("asc"))) { success = m_pGrid->LoadFromASC(fname, progress_callback); // vtElevationGrid does have its own ASC reader, but use GDAL instead // success = m_pGrid->LoadWithGDAL(strFileName.mb_str(wxConvUTF8), progress_callback, err); } else if (!strExt.CmpNoCase(_T("bil"))) { success = m_pGrid->LoadWithGDAL(fname, progress_callback, err); } else if (!strExt.CmpNoCase(_T("mem"))) { success = m_pGrid->LoadWithGDAL(fname, progress_callback, err); } else if (!strExt.CmpNoCase(_T("ter"))) { success = m_pGrid->LoadFromTerragen(fname, progress_callback); } else if (!strExt.CmpNoCase(_T("cdf"))) { success = m_pGrid->LoadWithGDAL(fname, progress_callback, err); } else if (!strExt.CmpNoCase(_T("hdr"))) { success = m_pGrid->LoadFromGTOPO30(fname, progress_callback); if (!success) success = m_pGrid->LoadFromGLOBE(fname, progress_callback); } else if (!strExt.CmpNoCase(_T("dte")) || !strExt.CmpNoCase(_T("dt0")) || !strExt.CmpNoCase(_T("dt1")) || !strExt.CmpNoCase(_T("dt2"))) { success = m_pGrid->LoadFromDTED(fname, progress_callback); } else if (!strExt.Left(3).CmpNoCase(_T("pgm"))) { success = m_pGrid->LoadFromPGM(fname, progress_callback); } else if (!strExt.CmpNoCase(_T("grd"))) { // might by CDF, might be Surfer GRD if (first == 'D') { VTLOG("First character is 'D', attempting load as a Surfer Grid file.\n"); success = m_pGrid->LoadFromGRD(fname, progress_callback); } else { VTLOG("First character is not 'D', attempting load as a netCDF file.\n"); success = m_pGrid->LoadWithGDAL(fname, progress_callback, err); } if (!success) { VTLOG("Didn't load successfully, attempting load with GDAL.\n"); // Might be 'Arc Binary Grid', try GDAL success = m_pGrid->LoadWithGDAL(fname, progress_callback, err); } } else if (!strFileName.Right(8).CmpNoCase(_T("catd.ddf")) || !strExt.Left(3).CmpNoCase(_T("tif")) || !strExt.Left(3).CmpNoCase(_T("png")) || !strExt.Left(3).CmpNoCase(_T("img")) || !strExt.CmpNoCase(_T("adf"))) { if (m_pGrid) success = m_pGrid->LoadWithGDAL(fname, progress_callback, err); } else if (!strExt.CmpNoCase(_T("raw"))) { RawDlg dlg(NULL, -1, _("Raw Elevation File")); dlg.m_iBytes = 2; dlg.m_iWidth = 100; dlg.m_iHeight = 100; dlg.m_fVUnits = 1.0f; dlg.m_fSpacing = 30.0f; dlg.m_bBigEndian = false; dlg.m_extents.SetToZero(); g_bld->GetProjection(dlg.m_original); if (dlg.ShowModal() == wxID_OK) { success = m_pGrid->LoadFromRAW(fname, dlg.m_iWidth, dlg.m_iHeight, dlg.m_iBytes, dlg.m_fVUnits, dlg.m_bBigEndian, progress_callback); } if (success) { m_pGrid->SetEarthExtents(dlg.m_extents); m_pGrid->SetProjection(dlg.m_proj); } } else if (!strExt.CmpNoCase(_T("ntf"))) { success = m_pGrid->LoadFromNTF5(fname, progress_callback); } else if (!strExt.CmpNoCase(_T("txt")) || !strExt.CmpNoCase(_T("xyz"))) { success = m_pGrid->LoadFromXYZ(fname, progress_callback); } else if (!strExt.CmpNoCase(_T("hgt"))) { success = m_pGrid->LoadFromHGT(fname, progress_callback); } else if (!strExt.Left(2).CmpNoCase(_T("db"))) { success = ImportFromDB(fname, progress_callback); } if (!success) return false; vtProjection *pProj; if (m_pGrid) pProj = &m_pGrid->GetProjection(); else pProj = &m_pTin->m_proj; // We should ask for a CRS before asking for extents if (!g_bld->ConfirmValidCRS(pProj)) { if (err) { err->type = vtElevError::CANCELLED; err->message = "Cancelled"; } return false; } if (m_pGrid != NULL) { if (m_pGrid->GetEarthExtents().IsEmpty()) { // No extents. wxString msg = _("File lacks geographic location (extents). Would you like to specify extents?\n Yes - specify extents\n No - use some default values\n"); int res = wxMessageBox(msg, _("Elevation Import"), wxYES_NO | wxCANCEL); if (res == wxYES) { DRECT ext; ext.SetToZero(); ExtentDlg dlg(NULL, -1, _("Elevation Grid Extents")); dlg.SetArea(ext, (pProj->IsGeographic() != 0)); if (dlg.ShowModal() == wxID_OK) m_pGrid->SetEarthExtents(dlg.m_area); else return false; } if (res == wxNO) { // Just make up some fake extents, assuming a regular even grid int xsize, ysize; m_pGrid->GetDimensions(xsize, ysize); DRECT ext; ext.left = ext.bottom = 0; if (pProj->IsGeographic()) { ext.right = xsize * (1.0/3600); // arc second ext.top = ysize * (1.0/3600); } else { ext.right = xsize * 10; // 10 linear units (meters, feet..) ext.top = ysize * 10; } m_pGrid->SetEarthExtents(ext); } if (res == wxCANCEL) { if (err) { err->type = vtElevError::CANCELLED; err->message = "Cancelled"; } return false; } } m_pGrid->SetupLocalCS(1.0f); } return true; }
void vtElevLayer::DrawLayerBitmap(wxDC *pDC, vtScaledView *pView) { if (!m_pGrid) return; // If we have grid data, but we don't yet have a bitmap to render it, then allocate if (m_pGrid->HasData() && m_pBitmap == NULL) SetupBitmap(pDC); if (m_pBitmap == NULL || !m_bBitmapRendered) { DrawLayerOutline(pDC, pView); return; } int iColumns, iRows; m_pGrid->GetDimensions(iColumns, iRows); DRECT screenrect = pView->WorldToCanvasD(m_pGrid->GetAreaExtents()); DRECT destRect = screenrect; wxRect srcRect(0, 0, m_ImageSize.x, m_ImageSize.y); double destRectW = (destRect.right - destRect.left); double destRectH = (destRect.bottom - destRect.top); double ratio_x = (float) srcRect.GetWidth() / destRectW; double ratio_y = (float) srcRect.GetHeight() / destRectH; #if 0 //clip stuff, so we only blit what we need int client_width, client_height; pView->GetClientSize(&client_width, &client_height); //get client window size if ((destRect.x + destRect.GetWidth() < 0) || (destRect.y + destRect.GetHeight() < 0) || (destRect.x > client_width) || (destRect.y > client_height)) //image completely off screen, return return; int diff; // clip left diff = 0 - destRect.x; if (diff > 0) { destRect.x += diff; srcRect.x += (long)(diff * ratio_x); } // clip top diff = 0 - destRect.y; if (diff > 0) { destRect.y += diff; srcRect.y += (long)(diff * ratio_y); } // clip right diff = destRect.x + destRect.GetWidth() - client_width; if (diff > 0) { destRect.width -= diff; srcRect.width -= (long)(diff * ratio_x); } // clip bottom diff = destRect.y + destRect.GetHeight() - client_height; if (diff > 0) { destRect.height -= diff; srcRect.height -= (long)(diff * ratio_y); } #endif bool bDrawNormal = true; #if WIN32 ::SetStretchBltMode((HDC) (pDC->GetHDC()), HALFTONE); if (!m_bHasMask) { // VTLOG("DrawBM %d, %d wh %d %d\n", (int) destRect.left, (int) destRect.top, // (int) destRectW, (int) destRectH); // Using StretchBlit is much faster and has less scaling/roundoff // problems than using the wx method DrawBitmap. However, GDI // won't stretch and mask at the same time! wxDC2 *pDC2 = (wxDC2 *) pDC; pDC2->StretchBlit(*m_pBitmap->m_pBitmap, destRect.left, destRect.top, destRectW, destRectH, srcRect.x, srcRect.y, srcRect.width, srcRect.height); bDrawNormal = false; } #endif if (bDrawNormal) { bool bUseDrawBitmap; #if wxCHECK_VERSION(2, 9, 0) bUseDrawBitmap = false; #else bUseDrawBitmap = true; // Older wx doesn't have StretchBlit #endif if (ratio_x > 1.0 && ratio_y > 1.0) bUseDrawBitmap = true; if (bUseDrawBitmap) { // Scale and draw the bitmap // Must use SetUserScale since wxWidgets doesn't provide StretchBlt? double scale_x = 1.0/ratio_x; double scale_y = 1.0/ratio_y; pDC->SetUserScale(scale_x, scale_y); // On Windows, this does a BitBlt (or MaskBlt if there is a mask) pDC->DrawBitmap(*m_pBitmap->m_pBitmap, (int) (destRect.left/scale_x), (int) (destRect.top/scale_y), m_bHasMask); // restore pDC->SetUserScale(1.0, 1.0); } #if wxCHECK_VERSION(2, 9, 0) else { // Create a memory DC; seems like a lot of overhead, but it also seems fast enough. wxMemoryDC temp_dc; temp_dc.SelectObject(*(m_pBitmap->m_pBitmap)); // Using StretchBlit seems to cause strange dark colors when zoomed out, but // that's better than the horizontal offset problems on zoomed-in that // resulted from using SetUserScale/DrawBitmap. pDC->StretchBlit(destRect.left, destRect.top, destRectW, destRectH, &temp_dc, srcRect.x, srcRect.y, srcRect.width, srcRect.height, wxCOPY, m_bHasMask); } #endif } }
bool vtElevLayer::WriteElevationTileset(TilingOptions &opts, BuilderView *pView) { // Avoid trouble with '.' and ',' in Europe ScopedLocale normal_numbers(LC_NUMERIC, "C"); // Check that options are valid CheckCompressionMethod(opts); // grid size int base_tilesize = opts.lod0size; int gridcols, gridrows; m_pGrid->GetDimensions(gridcols, gridrows); DRECT area = m_pGrid->GetEarthExtents(); DPoint2 tile_dim(area.Width()/opts.cols, area.Height()/opts.rows); DPoint2 cell_size = tile_dim / base_tilesize; const vtProjection &proj = m_pGrid->GetProjection(); vtString units = GetLinearUnitName(proj.GetUnits()); units.MakeLower(); int zone = proj.GetUTMZone(); vtString crs; if (proj.IsGeographic()) crs = "LL"; else if (zone != 0) crs = "UTM"; else crs = "Other"; // Try to create directory to hold the tiles vtString dirname = opts.fname; RemoveFileExtensions(dirname); if (!vtCreateDir(dirname)) return false; // We won't know the exact height extents until the tiles have generated, // so gather extents as we produce the tiles and write the INI later. float minheight = 1E9, maxheight = -1E9; ColorMap cmap; vtElevLayer::SetupDefaultColors(cmap); // defaults vtString dirname_image = opts.fname_images; RemoveFileExtensions(dirname_image); if (opts.bCreateDerivedImages) { if (!vtCreateDir(dirname_image)) return false; vtString cmap_fname = opts.draw.m_strColorMapFile; vtString cmap_path = FindFileOnPaths(vtGetDataPath(), "GeoTypical/" + cmap_fname); if (cmap_path == "") DisplayAndLog("Couldn't find color map."); else { if (!cmap.Load(cmap_path)) DisplayAndLog("Couldn't load color map."); } } ImageGLCanvas *pCanvas = NULL; #if USE_OPENGL wxFrame *frame = new wxFrame; if (opts.bCreateDerivedImages && opts.bUseTextureCompression && opts.eCompressionType == TC_OPENGL) { frame->Create(g_bld->m_pParentWindow, -1, _T("Texture Compression OpenGL Context"), wxPoint(100,400), wxSize(280, 300), wxCAPTION | wxCLIP_CHILDREN); pCanvas = new ImageGLCanvas(frame); } #endif // make a note of which lods exist LODMap lod_existence_map(opts.cols, opts.rows); bool bFloat = m_pGrid->IsFloatMode(); bool bJPEG = (opts.bUseTextureCompression && opts.eCompressionType == TC_JPEG); int i, j, lod; int total = opts.rows * opts.cols, done = 0; for (j = 0; j < opts.rows; j++) { for (i = 0; i < opts.cols; i++) { // We might want to skip certain tiles if (opts.iMinRow != -1 && (i < opts.iMinCol || i > opts.iMaxCol || j < opts.iMinRow || j > opts.iMaxRow)) continue; DRECT tile_area; tile_area.left = area.left + tile_dim.x * i; tile_area.right = area.left + tile_dim.x * (i+1); tile_area.bottom = area.bottom + tile_dim.y * j; tile_area.top = area.bottom + tile_dim.y * (j+1); int col = i; int row = opts.rows-1-j; // draw our progress in the main view if (pView) pView->ShowGridMarks(area, opts.cols, opts.rows, col, opts.rows-1-row); // Extract the highest LOD we need vtElevationGrid base_lod(tile_area, IPoint2(base_tilesize+1, base_tilesize+1), bFloat, proj); bool bAllInvalid = true; bool bAllZero = true; int iNumInvalid = 0; DPoint2 p; int x, y; for (y = base_tilesize; y >= 0; y--) { p.y = area.bottom + (j*tile_dim.y) + ((double)y / base_tilesize * tile_dim.y); for (x = 0; x <= base_tilesize; x++) { p.x = area.left + (i*tile_dim.x) + ((double)x / base_tilesize * tile_dim.x); float fvalue = m_pGrid->GetFilteredValue(p); base_lod.SetFValue(x, y, fvalue); if (fvalue == INVALID_ELEVATION) iNumInvalid++; else { bAllInvalid = false; // Gather height extents if (fvalue < minheight) minheight = fvalue; if (fvalue > maxheight) maxheight = fvalue; } if (fvalue != 0) bAllZero = false; } } // Increment whether we omit or not done++; // If there is no real data there, omit this tile if (bAllInvalid) continue; // Omit all-zero tiles (flat sea-level) if desired if (opts.bOmitFlatTiles && bAllZero) continue; // Now we know this tile will be included, so note the LODs present int base_tile_exponent = vt_log2(base_tilesize); lod_existence_map.set(i, j, base_tile_exponent, base_tile_exponent-(opts.numlods-1)); if (iNumInvalid > 0) { UpdateProgressDialog2(done*99/total, 0, _("Filling gaps")); bool bGood; int method = g_Options.GetValueInt(TAG_GAP_FILL_METHOD); if (method == 1) bGood = base_lod.FillGaps(NULL, progress_callback_minor); else if (method == 2) bGood = base_lod.FillGapsSmooth(NULL, progress_callback_minor); else if (method == 3) bGood = (base_lod.FillGapsByRegionGrowing(2, 5, progress_callback_minor) != -1); if (!bGood) return false; opts.iNoDataFilled += iNumInvalid; } // Create a matching derived texture tileset if (opts.bCreateDerivedImages) { // Create a matching derived texture tileset vtDIB dib; base_lod.ComputeHeightExtents(); if (opts.bImageAlpha) { dib.Create(IPoint2(base_tilesize, base_tilesize), 32); base_lod.ColorDibFromElevation(&dib, &cmap, 4000, RGBAi(0,0,0,0)); } else { dib.Create(IPoint2(base_tilesize, base_tilesize), 24); base_lod.ColorDibFromElevation(&dib, &cmap, 4000, RGBi(255,0,0)); } if (opts.draw.m_bShadingQuick) base_lod.ShadeQuick(&dib, SHADING_BIAS, true); else if (opts.draw.m_bShadingDot) { FPoint3 light_dir = LightDirection(opts.draw.m_iCastAngle, opts.draw.m_iCastDirection); // Don't cast shadows for tileset; they won't cast // correctly from one tile to the next. base_lod.ShadeDibFromElevation(&dib, light_dir, 1.0f, opts.draw.m_fAmbient, opts.draw.m_fGamma, true); } for (int k = 0; k < opts.numlods; k++) { vtString fname = MakeFilenameDB(dirname_image, col, row, k); int tilesize = base_tilesize >> k; vtMiniDatabuf output_buf; output_buf.xsize = tilesize; output_buf.ysize = tilesize; output_buf.zsize = 1; output_buf.tsteps = 1; output_buf.SetBounds(proj, tile_area); int depth = dib.GetDepth() / 8; int iUncompressedSize = tilesize * tilesize * depth; uchar *rgb_bytes = (uchar *) malloc(iUncompressedSize); uchar *dst = rgb_bytes; if (opts.bImageAlpha) { RGBAi rgba; for (int ro = 0; ro < base_tilesize; ro += (1<<k)) for (int co = 0; co < base_tilesize; co += (1<<k)) { dib.GetPixel32(co, ro, rgba); *dst++ = rgba.r; *dst++ = rgba.g; *dst++ = rgba.b; *dst++ = rgba.a; } } else { RGBi rgb; for (int ro = 0; ro < base_tilesize; ro += (1<<k)) for (int co = 0; co < base_tilesize; co += (1<<k)) { dib.GetPixel24(co, ro, rgb); *dst++ = rgb.r; *dst++ = rgb.g; *dst++ = rgb.b; } } // Write and optionally compress the image WriteMiniImage(fname, opts, rgb_bytes, output_buf, iUncompressedSize, pCanvas); // Free the uncompressed image free(rgb_bytes); } } for (lod = 0; lod < opts.numlods; lod++) { int tilesize = base_tilesize >> lod; vtString fname = MakeFilenameDB(dirname, col, row, lod); // make a message for the progress dialog wxString msg; msg.Printf(_("Writing tile '%hs', size %dx%d"), (const char *)fname, tilesize, tilesize); UpdateProgressDialog2(done*99/total, 0, msg); vtMiniDatabuf buf; buf.SetBounds(proj, tile_area); buf.alloc(tilesize+1, tilesize+1, 1, 1, bFloat ? 2 : 1); float *fdata = (float *) buf.data; short *sdata = (short *) buf.data; DPoint2 p; for (int y = base_tilesize; y >= 0; y -= (1<<lod)) { p.y = area.bottom + (j*tile_dim.y) + ((double)y / base_tilesize * tile_dim.y); for (int x = 0; x <= base_tilesize; x += (1<<lod)) { p.x = area.left + (i*tile_dim.x) + ((double)x / base_tilesize * tile_dim.x); if (bFloat) { *fdata = base_lod.GetFilteredValue(p); fdata++; } else { *sdata = (short) base_lod.GetFilteredValue(p); sdata++; } } } if (buf.savedata(fname) == 0) { // what should we do if writing a tile fails? } } } }
// // Use the QuikGrid library to generate a grid from a set of 3D points. // bool vtElevLayer::CreateFromPoints(vtFeatureSet *set, const IPoint2 &size, float fDistanceRatio) { #if SUPPORT_QUIKGRID vtFeatureSetPoint3D *fsp3 = dynamic_cast<vtFeatureSetPoint3D *>(set); if (!fsp3) return false; DRECT extent; fsp3->ComputeExtent(extent); int iMaxSize = fsp3->NumEntities(); ScatData sdata(iMaxSize); DPoint3 p; for (int i = 0; i < iMaxSize; i++) { fsp3->GetPoint(i, p); sdata.SetNext(p.x, p.y, p.z); } // Make a SurfaceGrid to hold the results DPoint2 spacing(extent.Width() / (size.x-1), extent.Height() / (size.y-1)); SurfaceGrid Zgrid(size.x, size.y); for (int x = 0; x < size.x; x++) Zgrid.xset(x, extent.left + spacing.x * x); for (int y = 0; y < size.y; y++) Zgrid.yset(y, extent.bottom + spacing.y * y); // "When any new points will not contributed more than 1/(scan bandwidth cutoff) // towards the value of a grid intersection scanning will cease in that // direction. " int x1 = XpandScanRatio(); // default 16, valid values 1..100 // "The Distance cutoff specifies a percent of the Density Distance" int x2 = XpandDensityRatio(); // default 150, valid values 1..10000 int x3 = XpandEdgeFactor(); // default 100, valid values 1..10000 float x4 = XpandUndefinedZ(); long x5 = XpandSample(); XpandDensityRatio((int) (fDistanceRatio * 100)); // Do the expand operation, gradually so we get progress XpandInit(Zgrid, sdata); int count = 0, total = size.x * size.y; while (XpandPoint( Zgrid, sdata)) { if ((count % 100) == 0) { if (progress_callback(count * 99 / total)) { // user cancelled return false; } } count++; } // copy the result to a ElevationGrid m_pGrid = new vtElevationGrid(extent, size, true, set->GetAtProjection()); for (int x = 0; x < size.x; x++) for (int y = 0; y < size.y; y++) { float value = Zgrid.z(x,y); if (value == -99999) m_pGrid->SetFValue(x, y, INVALID_ELEVATION); else m_pGrid->SetFValue(x, y, value); } m_pGrid->ComputeHeightExtents(); m_pGrid->SetupLocalCS(); return true; #else // No QuikGrid return false; #endif }
/** * Combine all vertices which are at the same location. By removing these * redundant vertices, the mesh will consume less space in memory and on disk. */ void vtTin::MergeSharedVerts(bool progress_callback(int)) { uint verts = NumVerts(); uint i, j; int bin; DRECT rect = m_EarthExtents; double width = rect.Width(); // make it slightly larger avoid edge condition rect.left -= 0.000001; width += 0.000002; m_bReplace = new int[verts]; m_vertbin = new Bin[BINS]; m_tribin = new Bin[BINS]; // sort the vertices into bins for (i = 0; i < verts; i++) { // flag all vertices initially not to remove m_bReplace[i] = -1; // find the correct bin, and add the index of this vertex to it bin = (int) (BINS * (m_vert[i].x - rect.left) / width); m_vertbin[bin].push_back(i); } uint trisize = m_tri.size(); for (i = 0; i < trisize; i++) { // find the correct bin, and add the index of this index to it bin = (int) (BINS * (m_vert[m_tri[i]].x - rect.left) / width); m_tribin[bin].push_back(i); } // compare within each bin, and between each adjacent bin, // looking for matching vertices to flag for removal for (bin = 0; bin < BINS; bin++) { if (progress_callback != NULL) progress_callback(bin * 100 / BINS); _CompareBins(bin, bin); if (bin < BINS-1) _CompareBins(bin, bin+1); } // now update each triangle index to point to the merge result for (bin = 0; bin < BINS; bin++) { if (progress_callback != NULL) progress_callback(bin * 100 / BINS); _UpdateIndicesInInBin(bin); } // now compact the vertex bins into a single array // make a copy to copy from DLine2 *vertcopy = new DLine2(m_vert); float *zcopy = new float[m_z.size()]; for (i = 0; i < m_z.size(); i++) zcopy[i] = m_z[i]; int inew = 0; // index into brand new array (actually re-using old) for (bin = 0; bin < BINS; bin++) { if (progress_callback != NULL) progress_callback(bin * 100 / BINS); uint binverts = m_vertbin[bin].size(); for (i = 0; i < binverts; i++) { int v_old = m_vertbin[bin].at(i); if (m_bReplace[v_old] != -1) continue; int v_new = inew; // copy old to new m_vert[v_new] = vertcopy->GetAt(v_old); m_z[v_new] = zcopy[v_old]; uint bintris = m_tribin[bin].size(); for (j = 0; j < bintris; j++) { int trindx = m_tribin[bin].at(j); if (m_tri[trindx] == v_old) m_tri[trindx] = v_new; } inew++; } } // our original array containers now hold the compacted result int newsize = inew; m_vert.SetSize(newsize); m_z.resize(newsize); // free up all the stuff we allocated delete [] m_bReplace; delete [] m_vertbin; delete [] m_tribin; delete vertcopy; delete [] zcopy; }