Esempio n. 1
0
/* Initialise the Trig tables */
bool trigInitialise(void)
{
	uint64_t test;
	uint32_t crc;
	uint32_t i;

	// Generate tables.
	STATIC_ASSERT(sizeof(trigSinTable)/sizeof(*trigSinTable) == 0x4001);
	for (i = 0; i != 0x4001; ++i)
	{
		trigSinTable[i] = (int)(0x10000*sin(i*(M_PI/0x8000)) + 0.5) - !!i;  // -!!i = subtract 1, unless i == 0.
	}
	STATIC_ASSERT(sizeof(trigAtanTable)/sizeof(*trigAtanTable) == 0x2001);
	for (i = 0; i != 0x2001; ++i)
	{
		trigAtanTable[i] = (int)(0x8000/M_PI*atan((double)i/0x2000) + 0.5);
	}

	// Check tables are correct.
	crc = ~crcSumU16(0, trigSinTable, sizeof(trigSinTable)/sizeof(*trigSinTable));
	ASSERT(crc == 0x6D3C8DB5, "Bad trigSinTable CRC = 0x%08X, sin function is broken.", crc);
	crc = ~crcSumU16(0, trigAtanTable, sizeof(trigAtanTable)/sizeof(*trigAtanTable));
	ASSERT(crc == 0xD2797F85, "Bad trigAtanTable CRC = 0x%08X, atan function is broken.", crc);

	// Test large and small square roots.
	for (test = 0x0000; test != 0x10000; ++test)
	{
		uint64_t lower = test*test;
		uint64_t upper = (test + 1)*(test + 1) - 1;
		ASSERT((uint32_t)iSqrt(lower) == test, "Sanity check failed, sqrt(%"PRIu64") gave %"PRIu32" instead of %"PRIu64"!", lower, i64Sqrt(lower), test);
		ASSERT((uint32_t)iSqrt(upper) == test, "Sanity check failed, sqrt(%"PRIu64") gave %"PRIu32" instead of %"PRIu64"!", upper, i64Sqrt(upper), test);
	}
	for (test = 0xFFFE0000; test != 0x00020000; test = (test + 1)&0xFFFFFFFF)
	{
		uint64_t lower = test*test;
		uint64_t upper = (test + 1)*(test + 1) - 1;
		ASSERT((uint32_t)i64Sqrt(lower) == test, "Sanity check failed, sqrt(%"PRIu64") gave %"PRIu32" instead of %"PRIu64"!", lower, i64Sqrt(lower), test);
		ASSERT((uint32_t)i64Sqrt(upper) == test, "Sanity check failed, sqrt(%"PRIu64") gave %"PRIu32" instead of %"PRIu64"!", upper, i64Sqrt(upper), test);
	}

	return true;
}
Esempio n. 2
0
int32_t iHypot3(int32_t x, int32_t y, int32_t z)
{
	return i64Sqrt((uint64_t)x*x + (uint64_t)y*y + (uint64_t)z*z);  // Casting from int32_t to uint64_t does sign extend.
}
Esempio n. 3
0
// Create a list of all tiles within the given radius, and the leftmost and rightmost angles of the tiles, for field of vision.
// Radius in tiles*TILE_UNITS.
// The droid is assumed to be at (dx = 0.5, dy = 0.5)*TILE_UNITS, not at the origin, since tile data is for the top left of the tile.
static std::vector<WavecastTile> generateWavecastTable(unsigned radius)
{
	std::vector<WavecastTile> tiles;

	std::vector<RationalAngle> unsortedAngles;

	for (unsigned diamond = 1; diamond*TILE_UNITS < radius*2; ++diamond)  // Factor is a bit more than needed to surround the circle with diamonds.
	{
		for (unsigned quadrant = 0; quadrant < 4; ++quadrant)
		{
			for (unsigned s = 0; s < diamond; ++s)
			{
				WavecastTile tile;
				switch (quadrant)
				{
					case 0: tile.dx =  diamond - s;     tile.dy =            s + 1; break;
					case 1: tile.dx =          - s;     tile.dy =  diamond - s;     break;
					case 2: tile.dx = -diamond + s + 1; tile.dy =          - s;     break;
					case 3: tile.dx =            s + 1; tile.dy = -diamond + s + 1; break;
				}
				const int sdx = tile.dx*2 - 1, sdy = tile.dy*2 - 1;  // 2*distance from sensor located at (0.5, 0.5)
				const unsigned tileRadiusSq = sdx*sdx + sdy*sdy;

				if (tileRadiusSq*(TILE_UNITS*TILE_UNITS/4) > radius*radius)
				{
					continue;
				}
				tile.invRadius = i64Sqrt((uint64_t)2*65536*65536 / tileRadiusSq);  // Result is at most 65536, inversely proportional to the radius.

				const int minCorner[4][2] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
				const int mcdx = minCorner[quadrant][0], mcdy = minCorner[quadrant][1];  // Corner of the tile which the minimum angle.
				RationalAngle minAngle = RationalAngle(tile.dx - 1 + mcdx, tile.dy - 1 + mcdy), maxAngle = RationalAngle(tile.dx - mcdx, tile.dy - mcdy);
				if (maxAngle < minAngle)
				{
					maxAngle = RationalAngle(0, 0);  // Special case, like RationalAngle(1, 0), except that it compares greater than all other angles instead of less than all other angles.
				}
				tile.angBegin = unsortedAngles.size();
				unsortedAngles.push_back(minAngle);
				tile.angEnd = unsortedAngles.size();
				unsortedAngles.push_back(maxAngle);

				tiles.push_back(tile);
			}
		}
	}

	// Sort the angles and remove duplicates.
	std::vector<RationalAngle> sortedAngles = unsortedAngles;
	std::sort(sortedAngles.begin(), sortedAngles.end());
	sortedAngles.erase(std::unique(sortedAngles.begin(), sortedAngles.end()), sortedAngles.end());

	// Subtitute the angle values angBegin and angEnd with ones that can be compared to each other, so that
	// the angles can be compared without using the unsortedAngles lookup table. (And without using the
	// sortedAngles lookup table either.)
	for (std::vector<WavecastTile>::iterator i = tiles.begin(); i != tiles.end(); ++i)
	{
		i->angBegin = std::lower_bound(sortedAngles.begin(), sortedAngles.end(), unsortedAngles[i->angBegin]) - sortedAngles.begin();
		i->angEnd   = std::lower_bound(sortedAngles.begin(), sortedAngles.end(), unsortedAngles[i->angEnd  ]) - sortedAngles.begin();
	}

#if 0  // Prints wavecast table.
	if (radius == 8*TILE_UNITS)
	{
		printf("Table for radius %f:\n", radius/(float)TILE_UNITS);
		for (std::vector<WavecastTile>::iterator i = tiles.begin(); i != tiles.end(); ++i)
			printf("Tile%5d: (%3d,%3d): angle %3d-%3d, invRadius %5d\n", (int)(i-/*>*/tiles.begin()), i->dx, i->dy, i->angBegin, i->angEnd, i->invRadius);
		printf("Unsorted angles for radius %f:\n", radius/(float)TILE_UNITS);
		for (std::vector<RationalAngle>::iterator i = unsortedAngles.begin(); i != unsortedAngles.end(); ++i)
			printf("Unsorted angle%5d: (%3d,%3d) = %11.6lf°\n", (int)(i-/*>*/unsortedAngles.begin()), ((int *)&*i)[0], ((int *)&*i)[1], atan2(((int *)&*i)[1], ((int *)&*i)[0])*180/M_PI);  // ((int *)&*i)[0] = very hacky bypass of "private:".
		printf("Sorted angles for radius %f:\n", radius/(float)TILE_UNITS);
		for (std::vector<RationalAngle>::iterator i = sortedAngles.begin(); i != sortedAngles.end(); ++i)
			printf("Sorted angle%5d: (%3d,%3d) = %11.6lf°\n", (int)(i-/*>*/sortedAngles.begin()), ((int *)&*i)[0], ((int *)&*i)[1], atan2(((int *)&*i)[1], ((int *)&*i)[0])*180/M_PI);  // ((int *)&*i)[0] = very hacky bypass of "private:".
	}
	printf("Radius %11.6f summary: %5d tiles, %5d angles (%5d with duplicates)\n", radius/(float)TILE_UNITS, (int)tiles.size(), (int)sortedAngles.size(), (int)unsortedAngles.size());
#endif

	return tiles;
}