Correcting 3D line drawing in C#
I have (with assistance) created a function that plots and draws a line of blocks within a 3D space. Generally this is performed in a 64x64x64 gridded cube.
This is the code I have:
internal static int DrawLine(Player theplayer, Byte drawBlock,
int x0, int y0, int z0, int x1, int y1, int z1)
{
int blocks = 0;
bool cannotUndo = false;
bool detected = false;
int dx = x1 - x0;
int dy = y1 - y0;
int dz = z1 - z0;
DrawOneBlock(theplayer, drawBlock, x0, y0, z0, ref blocks, ref cannotUndo);
if (Math.Abs(dx) > Math.Abs(dy) &&
Math.Abs(dx) > Math.Abs(dz) &&
detected == false)
{
detected = true;
float my = (float)dy / (float)dx;
float mz = (float)dz / (float)dx;
float by = y0 - my * x0;
float bz = z0 - mz * x0;
dx = (dx < 0) ? -1 : 1;
while (x0 != x1)
{
x0 += dx;
DrawOneBlock(theplayer, drawBlock,
Convert.ToInt32(x0),
Convert.ToInt32(Math.Round(my * x0 + by)),
Convert.ToInt32(Math.Round(mz * x0 + bz)),
ref blocks, ref cannotUndo);
}
}
if (Math.Abs(dy) > Math.Abs(dz) &&
Math.Abs(dy) > Math.Abs(dx) &&
detected == false)
{
detected = true;
float mz = (float)dz / (float)dy;
float mx = (float)dx / (float)dy;
float bz = z0 - mz * y0;
float bx = x0 - mx * y0;
dy = (dy < 0) ? -1 : 1;
while (y0 != y1)
{
y0 += dy;
DrawOneBlock(theplayer, drawBlock,
Convert.ToInt32(Math.Round(mx * y0 + bx)),
Convert.ToInt32(y0),
Convert.ToInt32(Math.Round(mz * y0 + bz)),
ref blocks, ref cannotUndo);
}
}
if (detected == false)
{
detected = true;
float mx = (float)dx / (float)dz;
float my = (float)dy / (float)dz;
float bx = x0 - mx * z0;
float by = y0 - my * z0;
dz = (dz < 0) ? -1 : 1;
while (z0 != z1)
{
z0 += dz;
DrawOneBlock(theplayer, drawBlock,
Convert.ToInt32(Math.Round(mx * z0 + bx)),
Convert.ToInt32(Math.Round(my * z0 + by)),
Convert.ToInt32(z0),
ref blocks, ref cannotUndo);
开发者_开发问答 }
}
return blocks;
}
It should queue up the block drawing and return the number of blocks it has drawn. The problem is that it is not drawing an un-broken line. In certain instances it leaves gaps between the blocks when at the very least all blocks should be connected by their vertices.
The only part of the code I struggled with is that I was calculating the largest difference in axis and creating a slope constant. I ran into an issue when trying to do a perfect diagonal line. All values were equal so I just defaulted to the z axis - this is where I believe the issue exists.
Maybe the Bresenham line algorithm modified to (hopefully) work in 3D could be an alternative for you?
public static void Swap<T>(ref T x, ref T y)
{
T tmp = y;
y = x;
x = tmp;
}
private void Draw3DLine(int x0, int y0, int z0, int x1, int y1, int z1)
{
bool steepXY = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
if (steepXY) { Swap(ref x0, ref y0); Swap(ref x1, ref y1); }
bool steepXZ = Math.Abs(z1 - z0) > Math.Abs(x1 - x0);
if (steepXZ) { Swap(ref x0, ref z0); Swap(ref x1, ref z1); }
int deltaX = Math.Abs(x1 - x0);
int deltaY = Math.Abs(y1 - y0);
int deltaZ = Math.Abs(z1 - z0);
int errorXY = deltaX / 2, errorXZ = deltaX / 2;
int stepX = (x0 > x1) ? -1 : 1;
int stepY = (y0 > y1) ? -1 : 1;
int stepZ = (z0 > z1) ? -1 : 1;
int y=y0, z=z0;
// Check if the end of the line hasn't been reached.
for(int x = x0; x!=x1; x+=stepX)
{
int xCopy=x, yCopy=y, zCopy=z;
if (steepXZ) Swap(ref xCopy, ref zCopy);
if (steepXY) Swap(ref xCopy, ref yCopy);
// Replace the WriteLine with your call to DrawOneBlock
Console.WriteLine("[" + xCopy + ", " + yCopy + ", " + zCopy + "], ");
errorXY -= deltaY;
errorXZ -= deltaZ;
if (errorXY < 0)
{
y += stepY;
errorXY += deltaX;
}
if (errorXZ < 0)
{
z += stepZ;
errorXZ += deltaX;
}
}
}
internal static void LineCallback(Player player, Position[] marks, object tag) //MODIFIED//
{
byte drawBlock = (byte)tag;
if (drawBlock == (byte)Block.Undefined)
{
drawBlock = (byte)player.lastUsedBlockType;
}
player.undoBuffer.Clear();
int blocks = 0;
bool cannotUndo = false;
// LINE CODE
int x1 = marks[0].x, y1 = marks[0].y, z1 = marks[0].h, x2 = marks[1].x, y2 = marks[1].y, z2 = marks[1].h;
int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
int[] pixel = new int[3];
pixel[0] = x1;
pixel[1] = y1;
pixel[2] = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
x_inc = (dx < 0) ? -1 : 1;
l = Math.Abs(dx);
y_inc = (dy < 0) ? -1 : 1;
m = Math.Abs(dy);
z_inc = (dz < 0) ? -1 : 1;
n = Math.Abs(dz);
dx2 = l << 1;
dy2 = m << 1;
dz2 = n << 1;
DrawOneBlock(player, drawBlock, x2, y2, z2, ref blocks, ref cannotUndo);
DrawOneBlock(player, drawBlock, x2, y2, z2, ref blocks, ref cannotUndo);
if ((l >= m) && (l >= n)) {
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++) {
DrawOneBlock(player, drawBlock, pixel[0], pixel[1], pixel[2], ref blocks, ref cannotUndo);
if (err_1 > 0) {
pixel[1] += y_inc;
err_1 -= dx2;
}
if (err_2 > 0) {
pixel[2] += z_inc;
err_2 -= dx2;
}
err_1 += dy2;
err_2 += dz2;
pixel[0] += x_inc;
}
} else if ((m >= l) && (m >= n)) {
err_1 = dx2 - m;
err_2 = dz2 - m;
for (i = 0; i < m; i++) {
DrawOneBlock(player, drawBlock, pixel[0], pixel[1], pixel[2], ref blocks, ref cannotUndo);
if (err_1 > 0) {
pixel[0] += x_inc;
err_1 -= dy2;
}
if (err_2 > 0) {
pixel[2] += z_inc;
err_2 -= dy2;
}
err_1 += dx2;
err_2 += dz2;
pixel[1] += y_inc;
}
} else {
err_1 = dy2 - n;
err_2 = dx2 - n;
for (i = 0; i < n; i++) {
DrawOneBlock(player, drawBlock, pixel[0], pixel[1], pixel[2], ref blocks, ref cannotUndo);
if (err_1 > 0) {
pixel[1] += y_inc;
err_1 -= dz2;
}
if (err_2 > 0) {
pixel[0] += x_inc;
err_2 -= dz2;
}
err_1 += dy2;
err_2 += dx2;
pixel[2] += z_inc;
}
}
// END LINE CODE
}
I don't understand the code, but based on the direction Jonas put me in I was able to implement this and test without flaw.
精彩评论