Пример #1
0
bool vtBuilding::GetBaseLevelCenter(DPoint2 &p) const
{
	DRECT rect;
	if (!GetExtents(rect))
		return false;
	rect.GetCenter(p);
	return true;
}
Пример #2
0
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);
	}
}
Пример #3
0
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);
	}
}
Пример #4
0
/**
 * 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);
			}
		}
	}
}
Пример #5
0
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);
	}
}
Пример #6
0
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);
}
Пример #7
0
//
// 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;
}
Пример #8
0
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;
	}
}
Пример #9
0
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);
		}
	}
}
Пример #10
0
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;
}
Пример #11
0
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
	}
}
Пример #12
0
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?
				}
			}
		}
	}
Пример #13
0
//
// 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
}
Пример #14
0
/**
 * 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;
}