@Override
  public void workOnSlice(int sliceNumber) {
    PrioritizableScene phantomScene = phantom;
    if (phantom instanceof AnalyticPhantom4D) {
      AnalyticPhantom4D scene4D = (AnalyticPhantom4D) phantom;
      phantomScene = scene4D.getScene(((double) sliceNumber) / trajectory.getProjectionStackSize());

      String disableAutoCenterBoolean =
          Configuration.getGlobalConfiguration()
              .getRegistryEntry(RegKeys.DISABLE_CENTERING_4DPHANTOM_PROJECTION_RENDERING);
      boolean disableAutoCenter = false;
      if (disableAutoCenterBoolean != null) {
        disableAutoCenter = Boolean.parseBoolean(disableAutoCenterBoolean);
      }

      Translation centerTranslation = new Translation(new SimpleVector(0, 0, 0));
      if (!disableAutoCenter) {
        SimpleVector center =
            SimpleOperators.add(
                    phantom.getMax().getAbstractVector(), phantom.getMin().getAbstractVector())
                .dividedBy(2);
        centerTranslation = new Translation(center.negated());
      }

      for (PhysicalObject o : phantomScene) {
        o.getShape().applyTransform(centerTranslation);
        // System.out.println(o.getShape().getMax() + " " + o.getShape().getMin());

        // Translate a part of XCAT to the center of source & detector for 2D projection (e.g. knee
        // at the center of the 2d projection)
        String translationString =
            Configuration.getGlobalConfiguration()
                .getRegistryEntry(RegKeys.GLOBAL_TRANSLATION_4DPHANTOM_PROJECTION_RENDERING);
        if (translationString != null) {
          // Center b/w RKJC & LKJC: -292.6426  211.7856  440.7783 (subj 5, static60),-401.1700
          // 165.9885  478.5600 (subj 2, static60)
          // XCAT Center by min & max: -177.73999504606988, 179.8512744259873, 312.19713254613583
          // translationVector = (XCAT Center by min & max) - (Center b/w RKJC & LKJC)=>
          // 114.9026, -31.9343, -128.5811 (subj5),  120, 3, -110(subj2) Try 114.0568    2.4778
          // -106.2550
          String[] values = translationString.split(", ");
          SimpleVector translationVector =
              new SimpleVector(
                  Double.parseDouble(values[0]),
                  Double.parseDouble(values[1]),
                  Double.parseDouble(values[2]));
          Translation translationToRotationCenter = new Translation(translationVector);
          o.getShape().applyTransform(translationToRotationCenter);
        }
      }
      // System.out.println(phantomScene.getMax() + " " + phantomScene.getMin());
    }
    Grid2D slice = raytraceScene(phantomScene, trajectory.getProjectionMatrix(sliceNumber));
    this.imageBuffer.add(slice, sliceNumber);
  }
  public void setTrajectory(
      int numProjectionMatrices,
      double sourceToAxisDistance,
      double averageAngularIncrement,
      double detectorOffsetX,
      double detectorOffsetY,
      CameraAxisDirection uDirection,
      CameraAxisDirection vDirection,
      SimpleVector rotationAxis,
      PointND rotationCenter,
      double angleFirstProjection) {
    this.projectionMatrices = new Projection[numProjectionMatrices];
    this.primaryAngles = new double[numProjectionMatrices];
    this.numProjectionMatrices = numProjectionMatrices;
    this.sourceToAxisDistance = sourceToAxisDistance;
    this.averageAngularIncrement = averageAngularIncrement;
    this.detectorOffsetU = detectorOffsetX;
    this.detectorOffsetV = detectorOffsetY;

    double cosPhi = Math.cos(General.toRadians(angleFirstProjection));
    double sinPhi = Math.sin(General.toRadians(angleFirstProjection));
    SimpleMatrix rotMat = new SimpleMatrix(3, 3);
    rotMat.setElementValue(0, 0, cosPhi);
    rotMat.setElementValue(0, 1, sinPhi);
    rotMat.setElementValue(1, 0, -sinPhi);
    rotMat.setElementValue(1, 1, cosPhi);
    rotMat.setElementValue(2, 2, 1);
    SimpleVector centerToCameraIdealAtInitialAngle =
        SimpleOperators.multiply(rotMat, new SimpleVector(sourceToAxisDistance, 0, 0));
    Plane3D trajPlane =
        new Plane3D(
            rotationAxis,
            SimpleOperators.multiplyInnerProd(rotationAxis, rotationCenter.getAbstractVector()));
    double distToPlane = trajPlane.computeDistance(new PointND(centerToCameraIdealAtInitialAngle));
    SimpleVector centerToCameraDir =
        SimpleOperators.subtract(
            SimpleOperators.add(
                rotationAxis.multipliedBy(-1 * distToPlane), centerToCameraIdealAtInitialAngle),
            rotationCenter.getAbstractVector());
    centerToCameraDir.divideBy(centerToCameraDir.normL2());
    SimpleVector centerToCameraInitialInPlane =
        centerToCameraDir.multipliedBy(sourceToAxisDistance);

    for (int i = 0; i < numProjectionMatrices; i++) {
      primaryAngles[i] = i * averageAngularIncrement + angleFirstProjection;
      // System.out.println(primaryAngles[i] + " " + averageAngularIncrement + " " +
      // this.reconDimensions[0] + " " + this.reconDimensions[1]);
      projectionMatrices[i] = new Projection();
      double rotationAngle = General.toRadians(primaryAngles[i]);
      projectionMatrices[i].setRtFromCircularTrajectory(
          rotationCenter.getAbstractVector(),
          rotationAxis,
          sourceToAxisDistance,
          centerToCameraInitialInPlane,
          uDirection,
          vDirection,
          rotationAngle);
      SimpleVector spacingUV = new SimpleVector(pixelDimensionX, pixelDimensionY);
      SimpleVector sizeUV = new SimpleVector(detectorWidth, detectorHeight);
      SimpleVector offset = new SimpleVector(detectorOffsetX, detectorOffsetY);
      projectionMatrices[i].setKFromDistancesSpacingsSizeOffset(
          sourceToDetectorDistance, spacingUV, sizeUV, offset, 1.0, 0);
    }
    this.projectionStackSize = numProjectionMatrices;
    // System.out.println("Defined geometry with SDD " +sourceToDetectorDistance);
  }