Возникли проблемы с созданием воксельной сферы

Я пытаюсь сгенерировать координаты для сферы с заданным радиусом, но мне удается создать только цилиндр, и я не совсем понимаю, почему. Вот мой текущий код:

function makeSphere(radius){
          var sphere3D = {};

          var radiusX = radius + 0.5;
          var radiusY = radius + 0.5;
          var radiusZ = radius + 0.5;

          var invRadiusX = 1 / radiusX;
          var invRadiusY = 1 / radiusY;
          var invRadiusZ = 1 / radiusZ;

          var ceilRadiusX = Math.ceil(radiusX);
          var ceilRadiusY = Math.ceil(radiusY);
          var ceilRadiusZ = Math.ceil(radiusZ);

          var nextXn = 0;
          forX: for (var x = 0; x <= ceilRadiusX; ++x) {
            var xn = nextXn;
            nextXn = (x + 1) * invRadiusX;
            var nextYn = 0;
            forY: for (var y = 0; y <= ceilRadiusY; ++y) {
              var yn = nextYn;
              nextYn = (y + 1) * invRadiusY;
              var nextZn = 0;
              forZ: for (var z = 0; z <= ceilRadiusZ; ++z) {
                var zn = nextZn;
                nextZn = (z + 1) * invRadiusZ;

                var distanceSq = lengthSq(xn, yn, zn);
                if (distanceSq > 1) {
                    if (z == 0) {
                        if (y == 0) {
                            break forX;
                        }
                        break forY;
                    }
                    break forZ;
                }


                if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) {
                    continue;
                }


                  sphere3D[[x,y,z]] = true;
                sphere3D[[-x,y,z]] = true;
                sphere3D[[x,-y,z]] = true;
                sphere3D[[x,y,-z]] = true;
                sphere3D[[-x,-y,z]] = true;
                sphere3D[[x,-y,-z]] = true;
                sphere3D[[-x,y,-z]] = true;
                sphere3D[[-x,-y,-z]] = true;

              }
            }
          }
        }


        function lengthSq(x, y, z) {
            return (x * x) + (y * y) + (z * z);
        }

        function lengthSq(x, z) {
            return (x * x) + (z * z);
        }

Что дает следующий вывод.

Есть идеи, где я ошибаюсь? Заранее спасибо за внимание.


person Jesus Sandro    schedule 03.01.2020    source источник
comment
У вас есть две функции, определенные под одним и тем же именем lengthSq() это не обязательно неправильно, но это запутает рецензентов. Также ваша функция makeSphere(radius) ничего не возвращает! Вы можете опубликовать свой полный код?   -  person helcode    schedule 03.01.2020
comment
Это может помочь   -  person Patrick Roberts    schedule 03.01.2020


Ответы (2)


Не уверен, что это решит вашу проблему, но у вас не может быть двух функций с одинаковым именем. В вашем случае второй lengthSq() заменит первый, даже если параметры разные.

В Javascript нет встроенной перегрузки функций. Однако вы можете попробовать эти предложения, если важно придерживаться одного и того же имени функции, которая обрабатывает несколько параметров. перегрузка в Javascript: рекомендации

Альтернативой является переименование его как lengthSqXZ(x, z), если вы используете его в другом месте вне предоставленного вами кода.

person John    schedule 03.01.2020

Вот подход, которому, возможно, будет легче следовать. Вы захотите разбить свой код на четыре части:

  • Генерация набора точек p в конкретной n-мерной области
  • Фильтрация набора точек на те q, которые находятся в пределах 1 единицы сферической поверхности, определяемой radius и n-мерным origin
  • Отражение набора точек на каждой из декартовых осей, пересекающихся в origin, для создания отраженного набора точек r
  • Добавление набора точек r к объекту nSphere

Ниже приведен набор функций, решающих каждую из этих проблем для создания n-сферы. .

// 0-sphere of radius 5 centered at [6]
console.log(makeNSphere(5, 6)); // { r: [6 - 5], [6 + 5] }
// 2-sphere of radius 2 centered at [0, 0, 0]
console.log(makeNSphere(2, 0, 0, 0));

function makeNSphere (radius, ...origin) {
  function onSurface (p) {
    const d = distance(
      p.map(
        (x, i) => x - origin[i]
      )
    );

    return Math.abs(d - radius) < 1;
  }

  const nSphere = {};
  const ps = range(
    ...origin.map(
      x => [x, x + radius + 1]
    )
  );
  const reflection = reflect(...origin);

  for (const q of where(ps, onSurface)) {
    for (const r of reflection(...q)) {
      nSphere[r] = true;
    }
  }

  return nSphere;
}

function distance (p) {
  let sum = 0;

  for (const x of p) {
    sum += x * x;
  }

  return Math.sqrt(sum);
}

function* range (constraints = [], ...rest) {
  const base = rest.length === 0;
  let begin = 0;
  let end = Infinity;
  let increment = 1;

  switch (constraints.length) {
    case 0: break;
    case 1: [end] = constraints; break;
    case 2: [begin, end] = constraints; break;
    default: [begin, end, increment] = constraints; break;
  }

  for (let i = begin; i < end; i += increment) {
    if (base) {
      yield [i];
      continue;
    }

    for (const a of range(...rest)) {
      yield [i, ...a];
    }
  }
}

function* where (ps, predicateFn) {
  for (const p of ps) {
    if (predicateFn(p)) {
      yield p;
    }
  }
}

function reflect (...axes) {
  return function* recurse (x, ...rest) {
    if (rest.length === 0) {
      yield* base(x);
      return;
    }

    for (const xs of recurse(...rest)) {
      yield* base(x, ...xs);
    }
  }

  function* base (x, ...rest) {
    yield [x, ...rest];

    const axis = axes[axes.length - rest.length - 1];
    const y = axis - (x - axis);

    if (x !== y) {
      yield [y, ...rest];
    }
  }
}

person Patrick Roberts    schedule 03.01.2020