bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & a_Dst) { if (a_Src.size() < 2) { // There are no midpoints, nothing to smooth return true; } // Smoothing: for each line segment, add points on its 1 / 4 lengths bool res = false; size_t Num = a_Src.size() - 2; // this many intermediary points a_Dst.clear(); a_Dst.reserve(Num * 2 + 2); cCaveDefPoints::const_iterator itr = a_Src.begin() + 1; const cCaveDefPoint & Source = a_Src.front(); a_Dst.push_back(Source); int PrevX = Source.m_BlockX; int PrevY = Source.m_BlockY; int PrevZ = Source.m_BlockZ; int PrevR = Source.m_Radius; for (size_t i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; int dy = itr->m_BlockY - PrevY; int dz = itr->m_BlockZ - PrevZ; if (abs(dx) + abs(dz) + abs(dy) < 6) { // Too short a segment to smooth-subdivide into quarters PrevX = itr->m_BlockX; PrevY = itr->m_BlockY; PrevZ = itr->m_BlockZ; PrevR = itr->m_Radius; continue; } int dr = itr->m_Radius - PrevR; int Rad1 = std::max(PrevR + 1 * dr / 4, 1); int Rad2 = std::max(PrevR + 3 * dr / 4, 1); a_Dst.push_back(cCaveDefPoint(PrevX + 1 * dx / 4, PrevY + 1 * dy / 4, PrevZ + 1 * dz / 4, Rad1)); a_Dst.push_back(cCaveDefPoint(PrevX + 3 * dx / 4, PrevY + 3 * dy / 4, PrevZ + 3 * dz / 4, Rad2)); PrevX = itr->m_BlockX; PrevY = itr->m_BlockY; PrevZ = itr->m_BlockZ; PrevR = itr->m_Radius; res = true; } a_Dst.push_back(a_Src.back()); return res && (a_Src.size() < a_Dst.size()); }
void cCaveTunnel::FinishLinear(void) { // For each segment, use Bresenham's 3D line algorithm to draw a "line" of defpoints cCaveDefPoints Pts; std::swap(Pts, m_Points); m_Points.reserve(Pts.size() * 3); cCaveDefPoint & PrevPoint = Pts.front(); int PrevX = PrevPoint.m_BlockX; int PrevY = PrevPoint.m_BlockY; int PrevZ = PrevPoint.m_BlockZ; for (cCaveDefPoints::const_iterator itr = Pts.begin() + 1, end = Pts.end(); itr != end; ++itr) { int x1 = itr->m_BlockX; int y1 = itr->m_BlockY; int z1 = itr->m_BlockZ; int dx = abs(x1 - PrevX); int dy = abs(y1 - PrevY); int dz = abs(z1 - PrevZ); int sx = (PrevX < x1) ? 1 : -1; int sy = (PrevY < y1) ? 1 : -1; int sz = (PrevZ < z1) ? 1 : -1; int R = itr->m_Radius; if (dx >= std::max(dy, dz)) // x dominant { int yd = dy - dx / 2; int zd = dz - dx / 2; for (;;) { m_Points.push_back(cCaveDefPoint(PrevX, PrevY, PrevZ, R)); if (PrevX == x1) { break; } if (yd >= 0) // move along y { PrevY += sy; yd -= dx; } if (zd >= 0) // move along z { PrevZ += sz; zd -= dx; } // move along x PrevX += sx; yd += dy; zd += dz; } } else if (dy >= std::max(dx, dz)) // y dominant { int xd = dx - dy / 2; int zd = dz - dy / 2; for (;;) { m_Points.push_back(cCaveDefPoint(PrevX, PrevY, PrevZ, R)); if (PrevY == y1) { break; } if (xd >= 0) // move along x { PrevX += sx; xd -= dy; } if (zd >= 0) // move along z { PrevZ += sz; zd -= dy; } // move along y PrevY += sy; xd += dx; zd += dz; } } else { // z dominant ASSERT(dz >= std::max(dx, dy)); int xd = dx - dz / 2; int yd = dy - dz / 2; for (;;) { m_Points.push_back(cCaveDefPoint(PrevX, PrevY, PrevZ, R)); if (PrevZ == z1) { break; } if (xd >= 0) // move along x { PrevX += sx; xd -= dz; } if (yd >= 0) // move along y { PrevY += sy; yd -= dz; } // move along z PrevZ += sz; xd += dx; yd += dy; } } // if (which dimension is dominant) } // for itr }