static void MakeFractalTerrain (dFloat* const elevation, int sizeInPowerOfTwos, dFloat elevationScale, dFloat roughness, dFloat maxElevation, dFloat minElevation)
	{
		float* map[4096 + 1];
		int size = (1 << sizeInPowerOfTwos) + 1;
		dAssert (size < int (sizeof (map) / sizeof map[0]));
		MakeMap (elevation, map, size);

		dFloat f = GetElevation (size, elevationScale, maxElevation, minElevation, roughness);
		map[0][0] = Guassian(f);
		map[0][size-1] = Guassian(f);
		map[size-1][0] = Guassian(f);
		map[size-1][size-1] = Guassian(f);
		for (int frequency = size - 1; frequency > 1; frequency = frequency / 2 ) {
			//dFloat f = pow (dFloat (frequency) * elevationScale, 1.0f + roughness);
			dFloat f = GetElevation (frequency, elevationScale, maxElevation, minElevation, roughness);

			for(int y0 = 0; y0 < (size - frequency); y0 += frequency) {
				int y1 = y0 + frequency / 2;
				int y2 = y0 + frequency;

				for(int x0 = 0; x0 < (size - frequency); x0 += frequency) {
					int x1 = x0 + frequency / 2;
					int x2 = x0 + frequency;

					map[y1][x1] = (map[y0][x0] + map[y0][x2] + map[y2][x0] + map[y2][x2]) * 0.25f + Guassian(f);

					map[y0][x1] = (map[y0][x0] + map[y0][x2]) * 0.5f + Guassian(f);
					map[y2][x1] = (map[y2][x0] + map[y2][x2]) * 0.5f + Guassian(f);

					map[y1][x0] = (map[y0][x0] + map[y2][x0]) * 0.5f + Guassian(f);
					map[y1][x2] = (map[y0][x2] + map[y2][x2]) * 0.5f + Guassian(f);

					// this trick eliminate the creases 
					#ifdef RE_SAMPLE_CORNER
						map[y0][x0] = (map[y0][x1] + map[y1][x0]) * 0.5f + Guassian(f);
						map[y0][x2] = (map[y0][x1] + map[y1][x2]) * 0.5f + Guassian(f);
						map[y2][x0] = (map[y1][x0] + map[y2][x1]) * 0.5f + Guassian(f);
						map[y2][x2] = (map[y2][x1] + map[y1][x2]) * 0.5f + Guassian(f);

//						map[y0][x1] = (map[y0][x0] + map[y0][x2]) * 0.5f + Guassian(f);
//						map[y2][x1] = (map[y2][x0] + map[y2][x2]) * 0.5f + Guassian(f);
//						map[y1][x0] = (map[y0][x0] + map[y2][x0]) * 0.5f + Guassian(f);
//						map[y1][x2] = (map[y0][x2] + map[y2][x2]) * 0.5f + Guassian(f);
					#endif
				}
			}
		}
	}
Example #2
0
void
EstimateThermalBase(const GeoPoint location, const fixed altitude,
                    const fixed average, const SpeedVector wind,
                    GeoPoint &ground_location, fixed &ground_alt)
{
  if (!positive(average))
    return;

  // Time spent in last thermal
  fixed Tmax = altitude / average;

  // Shortcut if no terrain available
  if (terrain == NULL) {
    ground_location = FindLatitudeLongitude(location, wind.bearing,
                                            wind.norm * Tmax);
    ground_alt = fixed_zero;
    return;
  }

  // Time of the 10 calculation intervals
  fixed dt = Tmax / 10;

  RasterTerrain::Lease map(*terrain);

  GeoPoint loc;
  // Iterate over 10 time-based calculation intervals
  for (fixed t = fixed_zero; t <= Tmax; t += dt) {
    // Calculate position
    loc = FindLatitudeLongitude(location, wind.bearing, wind.norm * t);
    // Calculate altitude
    fixed hthermal = altitude - average * t;
    // Calculate altitude above ground
    fixed dh = hthermal - GetElevation(map, loc);

    // Below ground level
    if (negative(dh)) {
      // Calculate time when we passed the ground level
      t = t + dh / average;
      // Calculate position
      loc = FindLatitudeLongitude(location, wind.bearing, wind.norm * t);
      break;
    }
  }

  ground_location = loc;
  ground_alt = GetElevation(map, ground_location);
}
Example #3
0
/**
 * Count the number of unknown (invalid) heixels in this grid.
 */
int vtHeightFieldGrid3d::FindNumUnknown()
{
	int count = 0;
	for (int i = 0; i < m_iSize.x; i++)
		for (int j = 0; j < m_iSize.y; j++)
			if (GetElevation(i, j) == INVALID_ELEVATION)
				count++;
	return count;
}
Example #4
0
/**
 * Use the height data in the grid and a colormap fill a bitmap with colors.
 * Any undefined heixels in the source will be fill with red (255,0,0).
 *
 * \param pBM			The bitmap to be colored.
 * \param color_map		A ColorMap which has already had GenerateColorTable() called.
 * \param nodata		The color to use for NODATA areas, where there are no elevation values.
 * \param progress_callback If supplied, this function will be called back
 *			with a value of 0 to 100 as the operation progresses.
 *
 * \return true if any invalid elevation values were encountered.
 */
bool vtHeightFieldGrid3d::ColorDibFromTable(vtBitmapBase *pBM, const ColorMap *color_map,
	const RGBAi &nodata, bool progress_callback(int)) const
{
	VTLOG1(" ColorDibFromTable:");
	const IPoint2 bitmap_size = pBM->GetSize();
	int depth = pBM->GetDepth();

	VTLOG(" dib size %d x %d, grid %d x %d.. ", bitmap_size.x, bitmap_size.y,
		m_iSize.x, m_iSize.y);

	const bool bExact = (bitmap_size == m_iSize);
	double ratiox = (double)(m_iSize.x - 1)/(bitmap_size.x - 1),
		   ratioy = (double)(m_iSize.y - 1)/(bitmap_size.y - 1);

	bool has_invalid = false;
	const RGBi nodata_24bit(nodata.r, nodata.g, nodata.b);
	float elev;

	// now iterate over the texels
	for (int i = 0; i < bitmap_size.x; i++)
	{
		if (progress_callback != NULL && (i&40) == 0)
			progress_callback(i * 100 / bitmap_size.x);

		// find the corresponding location in the height grid
		const double x = i * ratiox;

		for (int j = 0; j < bitmap_size.y; j++)
		{
			const double y = j * ratioy;

			if (bExact)
				elev = GetElevation(i, j, true);	// Always use true elevation
			else
				elev = GetInterpolatedElevation(x, y, true);	// Always use true elevation
			if (elev == INVALID_ELEVATION)
			{
				if (depth == 32)
					pBM->SetPixel32(i, bitmap_size.y - 1 - j, nodata);
				else
					pBM->SetPixel24(i, bitmap_size.y - 1 - j, nodata_24bit);
				has_invalid = true;
				continue;
			}
			const RGBi &rgb = color_map->ColorFromTable(elev);
			if (depth == 32)
				pBM->SetPixel32(i, bitmap_size.y - 1 - j, rgb);
			else
				pBM->SetPixel24(i, bitmap_size.y - 1 - j, rgb);
		}
	}
	VTLOG("Done.\n");
	return has_invalid;
}
Example #5
0
/**
 * Quickly produce a shading-like effect by scanning over the bitmap once,
 * using the east-west slope to produce lightening/darkening.
 * The bitmap must be the same size as the elevation grid, or a power of 2 smaller.
 */
void vtHeightFieldGrid3d::ShadeQuick(vtBitmapBase *pBM, float fLightFactor,
									 bool bTrue, bool progress_callback(int))
{
	const IPoint2 bitmap_size = pBM->GetSize();
	const int depth = pBM->GetDepth();

	const int stepx = m_iSize.x / bitmap_size.x;
	const int stepy = m_iSize.y / bitmap_size.y;

	RGBi rgb;
	RGBAi rgba;

	for (int j = 0; j < bitmap_size.y; j++)
	{
		if (progress_callback != NULL && (j%40) == 0)
				progress_callback(j * 100 / bitmap_size.y);

		// find corresponding location in heightfield
		const int y = m_iSize.y-1 - (j * stepy);
		for (int i = 0; i < bitmap_size.x; i++)
		{
			if (depth == 32)
				pBM->GetPixel32(i, j, rgba);
			else
				pBM->GetPixel24(i, j, rgb);

			int x_offset = 0;
			if (i == bitmap_size.x-1)
				x_offset = -1;

			// index into elevation
			const int x = i * stepx;
			float value = GetElevation(x + x_offset, y, bTrue);
			if (value == INVALID_ELEVATION)
			{
				// Do not touch pixels in nodata areas
				continue;
			}

			float value2 = GetElevation(x+1 + x_offset, y, bTrue);
			if (value2 == INVALID_ELEVATION)
				value2 = value;
			short diff = (short) ((value2 - value) / m_fStep.x * fLightFactor);

			// clip to keep values under control
			if (diff > 128)
				diff = 128;
			else if (diff < -128)
				diff = -128;
			if (depth == 32)
			{
				rgba.r += diff;
				rgba.g += diff;
				rgba.b += diff;
				if (rgba.r < 0) rgba.r = 0;
				else if (rgba.r > 255) rgba.r = 255;
				if (rgba.g < 0) rgba.g = 0;
				else if (rgba.g > 255) rgba.g = 255;
				if (rgba.b < 0) rgba.b = 0;
				else if (rgba.b > 255) rgba.b = 255;
				pBM->SetPixel32(i, j, rgba);
			}
			else
			{
				rgb.r = rgb.r + diff;
				rgb.g = rgb.g + diff;
				rgb.b = rgb.b + diff;
				if (rgb.r < 0) rgb.r = 0;
				else if (rgb.r > 255) rgb.r = 255;
				if (rgb.g < 0) rgb.g = 0;
				else if (rgb.g > 255) rgb.g = 255;
				if (rgb.b < 0) rgb.b = 0;
				else if (rgb.b > 255) rgb.b = 255;
				pBM->SetPixel24(i, j, rgb);
			}
		}
	}
}
Example #6
0
/**
 * Get the interpolated height of the grid at a specific grid coordinate,
 * where the coordinates can be non-integer; the result is interpolated
 * between the source heixels when possible (i.e. not at the edge)
 *
 * \param findex_x Floating point index, from 0 to width in heixels.
 * \param findex_y Floating point index, from 0 to height in heixels.
 * \param bTrue Use the true elevation, ignoring any scaling/exaggeration.
 */
float vtHeightFieldGrid3d::GetInterpolatedElevation(double findex_x, double findex_y,
	bool bTrue) const
{
	// Require the point to be inside the grid
	if (findex_x < 0 || findex_x > m_iSize.x-1)
		return INVALID_ELEVATION;
	if (findex_y < 0 || findex_y > m_iSize.y-1)
		return INVALID_ELEVATION;

	int index_x = (int) findex_x;
	int index_y = (int) findex_y;

	float diff_x = (float) (findex_x - index_x);
	float diff_y = (float) (findex_y - index_y);

	if (index_x == m_iSize.x-1)
	{
		// On right edge
		index_x --;
		diff_x = 1.0f;
	}
	if (index_y == m_iSize.y-1)
	{
		// On top edge
		index_y --;
		diff_y = 1.0f;
	}

	const float fDataBL = GetElevation(index_x, index_y, bTrue);
	const float fDataBR = GetElevation(index_x+1, index_y, bTrue);
	const float fDataTL = GetElevation(index_x, index_y+1, bTrue);
	const float fDataTR = GetElevation(index_x+1, index_y+1, bTrue);

	int valid = 0;
	if (fDataBL != INVALID_ELEVATION)
		valid++;
	if (fDataBR != INVALID_ELEVATION)
		valid++;
	if (fDataTL != INVALID_ELEVATION)
		valid++;
	if (fDataTR != INVALID_ELEVATION)
		valid++;

	float fData;
	if (valid == 4)	// all valid
	{
		// do bilinear filtering
		fData = (float) (fDataBL +
				(fDataBR-fDataBL)*diff_x +
				(fDataTL-fDataBL)*diff_y +
				(fDataTR-fDataTL-fDataBR+fDataBL)*diff_x*diff_y);
	}
	else if (valid > 0)
	{
		// Look for closest valid nearest neighbor
		float dist[4];
		float value[4];

		value[0] = fDataBL;
		value[1] = fDataBR;
		value[2] = fDataTL;
		value[3] = fDataTR;

		if (fDataBL != INVALID_ELEVATION)
			dist[0] = fabs(diff_x*diff_x) + fabs(diff_y*diff_y);
		else
			dist[0] = 3;	// Not valid, use a value > 2

		if (fDataBR != INVALID_ELEVATION)
			dist[1] = fabs((1-diff_x)*(1-diff_x)) + fabs(diff_y*diff_y);
		else
			dist[1] = 3;

		if (fDataTL != INVALID_ELEVATION)
			dist[2] = fabs(diff_x*diff_x) + fabs((1-diff_y)*(1-diff_y));
		else
			dist[2] = 3;

		if (fDataTR != INVALID_ELEVATION)
			dist[3] = fabs((1-diff_x)*(1-diff_x)) + fabs((1-diff_y)*(1-diff_y));
		else
			dist[3] = 3;

		float closest = 4;
		int closest_index;
		for (int i = 0; i < 4; i++)
		{
			if (dist[i] < closest)
			{
				closest = dist[i];
				closest_index = i;
			}
		}
		fData = value[closest_index];
	}
	else
		fData = INVALID_ELEVATION;

	return fData;
}
Example #7
0
void
EstimateThermalBase(const RasterTerrain *terrain,
                    const GeoPoint location, const double altitude,
                    const double average, const SpeedVector wind,
                    GeoPoint &ground_location, double &ground_alt)
{
  if (average <= 0 || altitude <= 0) {
    ground_location = location;
    ground_alt = 0;
    return;
  }

  // Max time the thermal could have risen for if ground
  // elevation is zero
  const auto Tmax = altitude / average;

  // Shortcut if no terrain available
  if (terrain == NULL) {
    ground_location = FindLatitudeLongitude(location, 
                                            wind.bearing,
                                            wind.norm * Tmax);
    ground_alt = 0;
    return;
  }

  RasterTerrain::Lease map(*terrain);

  // Height step of the 10 calculation intervals
  const auto dh = altitude / 10;

  // Iterate over 10 altitude-based calculation intervals
  // We do this because the terrain elevation may shift
  // as we trace the thermal back to its source

  GeoPoint loc = location;

  for (auto h = altitude; h >= 0; h -= dh) {
    // Time to descend to this height
    auto t = (altitude - h) / average;

    // Calculate position
    loc = FindLatitudeLongitude(location, wind.bearing, 
                                wind.norm * t);

    // Calculate altitude above ground
    auto dh = h - GetElevation(map, loc);

    // At or below ground level, use linear interpolation
    // to estimate intersection
    if (dh <= 0) {
      // Calculate time when we passed the ground level
      t += dh / average;

      if (t <= 0)
        /* can happen when the terrain at this location is higher than
           the aircraft's current altitude; bail out */
        break;

      // Calculate position
      loc = FindLatitudeLongitude(location, wind.bearing, 
                                  wind.norm * t);
      break;
    }
  }

  ground_location = loc;
  ground_alt = GetElevation(map, ground_location);
}
Example #8
0
/**
 * Quickly produce a shading-like effect by scanning over the bitmap once,
 * using the east-west slope to produce lightening/darkening.
 * The bitmap must be the same size as the elevation grid, or a power of 2 smaller.
 */
void vtHeightFieldGrid3d::ShadeQuick(vtBitmapBase *pBM, float fLightFactor,
									 bool bTrue, bool progress_callback(int))
{
	int w = pBM->GetWidth();
	int h = pBM->GetHeight();
	int depth = pBM->GetDepth();

	int stepx = m_iColumns / w;
	int stepy = m_iRows / h;

	int i, j;	// indices into bitmap
	int x, y;	// indices into elevation

	RGBi rgb;
	RGBAi rgba;

	for (j = 0; j < h; j++)
	{
		if (progress_callback != NULL)
		{
			if ((j&7) == 0)
				progress_callback(j * 100 / h);
		}
		// find corresponding location in heightfield
		y = m_iRows-1 - (j * stepy);
		for (i = 0; i < w; i++)
		{
			if (depth == 32)
				pBM->GetPixel32(i, j, rgba);
			else
				pBM->GetPixel24(i, j, rgb);

			int x_offset = 0;
			if (i == w-1)
				x_offset = -1;

			x = i * stepx;
			float value = GetElevation(x + x_offset, y, bTrue);
			if (value == INVALID_ELEVATION)
			{
				// Do not touch pixels in nodata areas
				continue;
			}

			float value2 = GetElevation(x+1 + x_offset, y, bTrue);
			if (value2 == INVALID_ELEVATION)
				value2 = value;
			short diff = (short) ((value2 - value) / m_fXStep * fLightFactor);

			// clip to keep values under control
			if (diff > 128)
				diff = 128;
			else if (diff < -128)
				diff = -128;
			if (depth == 32)
			{
				rgba.r += diff;
				rgba.g += diff;
				rgba.b += diff;
				if (rgba.r < 0) rgba.r = 0;
				else if (rgba.r > 255) rgba.r = 255;
				if (rgba.g < 0) rgba.g = 0;
				else if (rgba.g > 255) rgba.g = 255;
				if (rgba.b < 0) rgba.b = 0;
				else if (rgba.b > 255) rgba.b = 255;
				pBM->SetPixel32(i, j, rgba);
			}
			else
			{
				rgb.r = rgb.r + diff;
				rgb.g = rgb.g + diff;
				rgb.b = rgb.b + diff;
				if (rgb.r < 0) rgb.r = 0;
				else if (rgb.r > 255) rgb.r = 255;
				if (rgb.g < 0) rgb.g = 0;
				else if (rgb.g > 255) rgb.g = 255;
				if (rgb.b < 0) rgb.b = 0;
				else if (rgb.b > 255) rgb.b = 255;
				pBM->SetPixel24(i, j, rgb);
			}
		}
	}
}
Example #9
0
/**
 * Use the height data in the grid and a colormap fill a bitmap with colors.
 * Any undefined heixels in the source will be fill with red (255,0,0).
 *
 * \param pBM			The bitmap to be colored.
 * \param table			The table of colors.
 * \param fMin, fMax	The range of valid elevation values expect in the input.
 * \param nodata		The color to use for NODATA areas, where there are no elevation values.
 * \param progress_callback If supplied, this function will be called back
 *			with a value of 0 to 100 as the operation progresses.
 *
 * \return true if any invalid elevation values were encountered.
 */
bool vtHeightFieldGrid3d::ColorDibFromTable(vtBitmapBase *pBM,
	   std::vector<RGBi> &table, float fMin, float fMax, const RGBAi &nodata,
	   bool progress_callback(int))
{
	VTLOG1(" ColorDibFromTable:");
	int w = pBM->GetWidth();
	int h = pBM->GetHeight();
	int depth = pBM->GetDepth();
	int gw, gh;
	GetDimensions(gw, gh);

	VTLOG(" dib size %d x %d, grid %d x %d.. ", w, h, gw, gh);

	bool bExact = (w == gw && h == gh);
	double ratiox = (double)(gw-1)/(w-1), ratioy = (double)(gh-1)/(h-1);

	float fRange = fMax - fMin;
	uint iGranularity = table.size()-1;
	bool has_invalid = false;
	RGBi nodata_24bit(nodata.r, nodata.g, nodata.b);
	double x, y;
	float elev;

	// now iterate over the texels
	for (int i = 0; i < w; i++)
	{
		if (progress_callback != NULL)
		{
			if ((i&7) == 0)
				progress_callback(i * 100 / w);
		}
		x = i * ratiox;		// find corresponding location in height grid

		for (int j = 0; j < h; j++)
		{
			y = j * ratioy;

			if (bExact)
				elev = GetElevation(i, j);
			else
				elev = GetInterpolatedElevation(x, y);
			if (elev == INVALID_ELEVATION)
			{
				if (depth == 32)
					pBM->SetPixel32(i, h-1-j, nodata);
				else
					pBM->SetPixel24(i, h-1-j, nodata_24bit);
				has_invalid = true;
				continue;
			}
			uint table_entry = (uint) ((elev - fMin) / fRange * iGranularity);
			if (table_entry > iGranularity-1)
				table_entry = iGranularity-1;
			if (depth == 32)
				pBM->SetPixel32(i, h-1-j, table[table_entry]);
			else
				pBM->SetPixel24(i, h-1-j, table[table_entry]);
		}
	}
	VTLOG("Done.\n");
	return has_invalid;
}