Beispiel #1
0
  public void updateSpringPosition() {
    if (mPrev != null && mSimulate) {
      mWorldPosition.set(mPrev.mWorldEndPosition);

      mWorldRotation.set(mRotation.getQuaternion());
      mWorldRotation.multiply(mPrev.mWorldRotation);

      MathUtil.setVectorToSumOf(
          mWorldEndPosition,
          mPrev.mWorldEndPosition,
          MathUtil.setVectorToProductOf(mTempVec1, mWorldRotation, mDirection));

      mWorldSpringRotation.set(mOriginalRotation);
      mWorldSpringRotation.multiply(mPrev.mWorldRotation);

      /* Method using only existing ngin3d (requires allocations/garbage)
       * mWorldSpringPosition.set(mPrev.mWorldEndPosition);
       * mWorldSpringPosition = mWorldSpringPosition.add(mWorldSpringRotation.applyTo(mDirection));
       * */

      // Method using new functions.
      MathUtil.setVectorToSumOf(
          mWorldSpringPosition,
          mPrev.mWorldEndPosition,
          MathUtil.setVectorToProductOf(mTempVec1, mWorldSpringRotation, mDirection));
    }
  }
  /**
   * Change the parent of a game object.
   *
   * <p>TODO: add code so that the object does not change its global position, rotation or scale
   * when it is reparented.
   *
   * @param newParent
   */
  public void setParent(GameObject newParent) {

    GameObject oldParent = this.myParent;

    double oldLocalRotation = this.getRotation();
    double newLocalRotation =
        MathUtil.normaliseAngle(
            oldParent.getGlobalRotation() - newParent.getGlobalRotation() + oldLocalRotation);

    double oldLocalScale = this.getScale();
    double newLocalScale = oldParent.getGlobalScale() * oldLocalScale / newParent.getGlobalScale();

    double[] globalPosition = this.getGlobalPosition();

    double[] globalPositionPoint = new double[3];
    globalPositionPoint[0] = globalPosition[0];
    globalPositionPoint[1] = globalPosition[1];
    globalPositionPoint[2] = 1;

    double[] newLocalPositionPoint =
        MathUtil.multiply(newParent.getInverseGlobalMatrix(), globalPositionPoint);

    double[] newLocalPosition = new double[2];
    newLocalPosition[0] = newLocalPositionPoint[0];
    newLocalPosition[1] = newLocalPositionPoint[1];

    myParent.myChildren.remove(this);
    myParent = newParent;
    myParent.myChildren.add(this);

    this.myTranslation = newLocalPosition;
    this.myRotation = newLocalRotation;
    this.myScale = newLocalScale;
  }
Beispiel #3
0
  public void projectBy(ProjectionParameters projectionParameters) {
    this.setWeeklyRent(
        MathUtil.increaseBy(this.getWeeklyRent(), projectionParameters.getRentIncreaseRate()));
    this.setMarketValue(
        MathUtil.increaseBy(this.getMarketValue(), projectionParameters.getCapitalGrowthRate()));
    this.ongoingCosts.projectBy(projectionParameters.getCpi());

    for (Owner owner : getOwnerList()) {
      owner.setAnnualIncome(
          MathUtil.increaseBy(
              owner.getAnnualIncome(), projectionParameters.getSalaryIncreaseRate()));
    }
  }
Beispiel #4
0
 @Test
 public void testCubicRealRoots() {
   assertCollection(AlgebraUtil.cubicRealRoots(0, 0, 0), 0, 0, 0);
   assertCollection(AlgebraUtil.cubicRealRoots(0, 0, 1), -1);
   assertCollection(
       AlgebraUtil.cubicRealRoots(0, 0, -1000000000000000000000000000000000.0), 100000000000.0);
   assertCollection(AlgebraUtil.cubicRealRoots(-3, 3, -1), 1, 1, 1);
   assertCollection(AlgebraUtil.cubicRealRoots(1, -1, -1), 1, -1, -1);
   assertCollection(MathUtil.simpleRound(10, AlgebraUtil.cubicRealRoots(-14, 56, -64)), 2, 4, 8);
   assertCollection(
       MathUtil.simpleRound(10, AlgebraUtil.cubicRealRoots(-0.875, 0.21875, -0.015625)),
       0.5,
       0.25,
       0.125);
 }
Beispiel #5
0
 public static Map<String, String> getEntityPropertiesToStringMap(
     Object entity, Map<String, String> fieldClassMapping, String... entityIdentifier) {
   Map<String, String> propertiesMap = new HashMap<String, String>();
   StringBuffer sb = new StringBuffer();
   if (entityIdentifier.length > 0) {
     for (String ei : entityIdentifier) {
       sb.append(ei + ".");
     }
   }
   String prefixStr = sb.toString();
   PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(entity.getClass());
   for (PropertyDescriptor pd : pds) {
     Method readMethod = pd.getReadMethod();
     if (null == readMethod) continue;
     Class<?> returnType = readMethod.getReturnType();
     Object returnValue = null;
     try {
       returnValue = readMethod.invoke(entity);
     } catch (IllegalArgumentException e) {
       e.printStackTrace();
     } catch (IllegalAccessException e) {
       e.printStackTrace();
     } catch (InvocationTargetException e) {
       e.printStackTrace();
     }
     if (null != returnValue) {
       String value = "";
       if (returnType.isAssignableFrom(Set.class)) {
         continue;
       } else if (isTenwaEntity(returnType)) {
         String fieldName = null;
         if (null != fieldClassMapping) {
           fieldName = fieldClassMapping.get(returnType.getSimpleName());
         }
         if (StringUtils.isBlank(fieldName)) {
           fieldName = "id";
         }
         Method method = BeanUtils.getPropertyDescriptor(returnType, fieldName).getReadMethod();
         // System.out.println("####:"+method.getName()+","+returnValue);
         try {
           value = StringUtil.nullToString(method.invoke(returnValue));
         } catch (IllegalArgumentException e) {
           e.printStackTrace();
         } catch (IllegalAccessException e) {
           e.printStackTrace();
         } catch (InvocationTargetException e) {
           e.printStackTrace();
         }
       } else {
         if (returnType.getSimpleName().equalsIgnoreCase("double")) {
           value = MathUtil.decimal((Double) returnValue, 8);
         } else {
           value = returnValue.toString();
         }
       }
       propertiesMap.put(prefixStr + pd.getName().toLowerCase(), value);
     }
   }
   return propertiesMap;
 }
Beispiel #6
0
  /**
   * http://ogre.sourcearchive.com/documentation/1.4.5/classOgre_1_1Vector3_eeef4472ad0c4d5f34a038a9f2faa819.html#eeef4472ad0c4d5f34a038a9f2faa819
   *
   * @param direction
   * @return
   */
  public Quaternion getRotationTo(Number3D direction) {
    // Based on Stan Melax's article in Game Programming Gems
    Quaternion q = new Quaternion();
    // Copy, since cannot modify local
    Number3D v0 = this;
    Number3D v1 = direction;
    v0.normalize();
    v1.normalize();

    float d = Number3D.dot(v0, v1);
    // If dot == 1, vectors are the same
    if (d >= 1.0f) {
      q.setIdentity();
    }
    if (d < 0.000001f - 1.0f) {
      // Generate an axis
      Number3D axis = Number3D.cross(Number3D.getAxisVector(Axis.X), this);
      if (axis.length() == 0) // pick another if colinear
      axis = Number3D.cross(Number3D.getAxisVector(Axis.Y), this);
      axis.normalize();
      q.fromAngleAxis(MathUtil.radiansToDegrees(MathUtil.PI), axis);
    } else {
      float s = FloatMath.sqrt((1 + d) * 2);
      float invs = 1f / s;

      Number3D c = Number3D.cross(v0, v1);

      q.x = c.x * invs;
      q.y = c.y * invs;
      q.z = c.z * invs;
      q.w = s * 0.5f;
      q.normalize();
    }
    return q;
  }
Beispiel #7
0
 @Override
 public boolean compare(Number actual, Number expected) {
   checkTolerance(tolerance);
   double actualDouble = checkNotNull(actual).doubleValue();
   double expectedDouble = checkNotNull(expected).doubleValue();
   return MathUtil.equalWithinTolerance(actualDouble, expectedDouble, tolerance);
 }
Beispiel #8
0
  public void updateNodeRotation() {
    if (mPrev != null && mSimulate) {
      Quaternion qRot = mRotation.getQuaternion();
      mTempQuat.set(
          mPrev.mWorldRotation.getQ0(),
          -mPrev.mWorldRotation.getQ1(),
          -mPrev.mWorldRotation.getQ2(),
          -mPrev.mWorldRotation.getQ3());
      qRot.set(mWorldRotation);
      qRot.multiply(mTempQuat);
      qRot.nor();

      /* After pointing, the rotation will have an arbitrary "roll" around
       * the "to" z-axis.  We must find the new position of the "up" vector
       * after rotation.
       */
      // Vec3 dir = qRot.applyTo(BONE_DIR);
      // Vec3 rolledUp = qRot.applyTo(BONE_ORTH);
      MathUtil.setVectorToProductOf(mTempVec1, qRot, BONE_DIR);
      MathUtil.setVectorToProductOf(mTempVec2, qRot, BONE_ORTH);

      /* We now project this vector and the original "up" vector onto a plane
       * perpendicular to the "to" vector so that we can find the extra
       * rotation needed to rotate the rolled "up" vector onto the given
       * "up" vector. Note that these vectors won't have unit length.
       */
      // Vec3 upProjected = mOrthogonalTarget.subtract(Vec3.dotProduct(mTempVec1,
      // mOrthogonalTarget), mTempVec1);
      float dot = Vec3.dotProduct(mTempVec1, mOrthogonalTarget);
      mTempVec3.set(dot * mTempVec1.x, dot * mTempVec1.y, dot * mTempVec1.z);
      MathUtil.setVectorToDifferenceOf(mTempVec4, mOrthogonalTarget, mTempVec3);

      /* Calculate the rotation bring rolledUpProjected onto upProjected.
       * Note that this rotation will be around the "to" vector (because both
       * vectors are parallel to the "to" vector after projection).
       */
      // Rotation rollRotation = Rotation.fromTo(mTempVec2, upProjected);
      // qRot.multiply(rollRotation.getQuaternion());
      MathUtil.setQuaternionFromTo(mTempQuat, mTempVec2, mTempVec4);
      qRot.multiply(mTempQuat);

      mTempRot.getQuaternion().set(qRot);
      mTempRot.getQuaternion().multiply(mPhysics.mFold);
      mActorNode.setRotation(mTempRot);
    }
  }
 /**
  * Compute the object's rotation in the global coordinate frame
  *
  * <p>TODO: Write this method
  *
  * @return the global rotation of the object (in degrees)
  */
 public double getGlobalRotation() {
   double rotation;
   if (myParent == null) {
     rotation = myRotation;
   } else {
     rotation = MathUtil.normaliseAngle(myParent.getGlobalRotation() + myRotation);
   }
   return rotation;
 }
 public static Number variance(Collection<? extends Number> col) {
   double mean = mean(col).doubleValue();
   double accumSum = 0;
   for (Number n : col) {
     accumSum += MathUtil.sq(n.doubleValue() - mean);
   }
   accumSum /= col.size();
   return accumSum;
 }
Beispiel #11
0
  public void updateNodePosition() {
    if (mPrev != null && mSimulate) {
      // Vec3 oldPos = new Vec3(mWorldEndPosition);
      mTempVec1.set(mWorldEndPosition);
      float damping = mPhysics.mDamping * mGlobalPhysics.mExtraDamping;
      float springStrength = mPhysics.mSpringStrength;
      for (int i = 0; i != 4; ++i) {
        mVelocity.x += mGlobalPhysics.mGravity.x;
        mVelocity.y += mGlobalPhysics.mGravity.y;
        mVelocity.z += mGlobalPhysics.mGravity.z;

        float strength = springStrength * ((1f / mRootiness) + 0.5f);

        mVelocity.x += (mWorldSpringPosition.x - mWorldEndPosition.x) * strength;
        mVelocity.y += (mWorldSpringPosition.y - mWorldEndPosition.y) * strength;
        mVelocity.z += (mWorldSpringPosition.z - mWorldEndPosition.z) * strength;

        mVelocity.x *= damping;
        mVelocity.y *= damping;
        mVelocity.z *= damping;
        mWorldEndPosition.x += 0.01f * mVelocity.x;
        mWorldEndPosition.y += 0.01f * mVelocity.y;
        mWorldEndPosition.z += 0.01f * mVelocity.z;
        if (mWorldEndPosition.z < -0.2f) {
          mWorldEndPosition.z = -0.2f;
          mVelocity.z = 0f;
        }
      }

      // Vec3 from = oldPos.subtract(mPrev.mWorldEndPosition);
      // Vec3 to = mWorldEndPosition.subtract(mPrev.mWorldEndPosition);
      // mWorldRotation.multiply(Rotation.fromTo(from, to).getQuaternion());

      // from = old_world_position - parent_end
      MathUtil.setVectorToDifferenceOf(mTempVec2, mTempVec1, mPrev.mWorldEndPosition);
      // to = new_world_position - parent_end
      MathUtil.setVectorToDifferenceOf(mTempVec3, mWorldEndPosition, mPrev.mWorldEndPosition);
      mWorldRotation.multiply(MathUtil.setQuaternionFromTo(mTempQuat, mTempVec2, mTempVec3));
    }
  }
Beispiel #12
0
 public static <T> T getRandomElement(final Set<T> collection) {
   if (collection == null || collection.size() == 0) {
     return null;
   }
   final int elemIndex = MathUtil.randomInteger(collection.size());
   int i = -1;
   for (final T elem : collection) {
     if (++i == elemIndex) {
       return elem;
     }
   }
   return collection.iterator().next();
 }
Beispiel #13
0
  // incorporates exponential model of probability of motion, weight less likely motions less
  private double[] constructW(double[] Uxyzrpy) {
    assert (Uxyzrpy.length == Vxyzrpy.length) : "Warning expected 6 velocity";

    double[] W = new double[6]; // weighting matrix

    for (int i = 0; i < Uxyzrpy.length; i++) {
      double u = Uxyzrpy[i];
      double v = Vxyzrpy[i];
      double Dv = Math.abs(u - v);

      if (i <= 2) {
        // handle velocities close to 0
        if ((Math.abs(u) <= LV_THRESH) && (Math.abs(v) <= LV_THRESH)) {
          // use exponential model to come up with weights
          W[i] = MathUtil.exp(-ALPHA * Dv);
        } // if our change in velocity was within acceptable bounds
        else if ((Dv / u) <= DELTAV_THRESH) {
          // use exponential model to come up with weights
          W[i] = MathUtil.exp(-ALPHA * Dv);
        } else {
          W[i] = 0; // throw out bad changes
        }
      } else {
        // handle angular velocities close to 0
        if ((Math.abs(u) <= LR_THRESH) && (Math.abs(v) <= LR_THRESH)) {
          // use exponential model to come up with weights
          W[i] = MathUtil.exp(-BETA * Dv);
        } // if our change in velocity was within acceptable bounds
        else if ((Dv / u) <= DELTAR_THRESH) {
          // use exponential model to come up with weights
          W[i] = MathUtil.exp(-BETA * Dv);
        } else {
          W[i] = 0; // throw out bad changes
        }
      }
    }
    return W;
  }
 /**
  * Compute the object's position in world coordinates
  *
  * <p>TODO: Write this method
  *
  * @return a point in world coordinats in [x,y] form
  */
 public double[] getGlobalPosition() {
   double[] globalPosition = new double[2];
   if (myParent == null) {
     globalPosition[0] = myTranslation[0];
     globalPosition[1] = myTranslation[1];
   } else {
     double[][] parentsGlobalMatrix = myParent.getGlobalMatrix();
     double[] positionPoint = new double[3];
     positionPoint[0] = myTranslation[0];
     positionPoint[1] = myTranslation[1];
     positionPoint[2] = 1;
     double[] globalPositionPoint = MathUtil.multiply(parentsGlobalMatrix, positionPoint);
     globalPosition[0] = globalPositionPoint[0];
     globalPosition[1] = globalPositionPoint[1];
   }
   return globalPosition;
 }
  public double[][] getGlobalMatrix() {
    double[] myGlobalPosition = this.getGlobalPosition();
    double[][] myGlobalTranslationMatrix = MathUtil.translationMatrix(myGlobalPosition);

    double myGlobalRotation = this.getGlobalRotation();
    double[][] myGlobalRotationMatrix = MathUtil.rotationMatrix(myGlobalRotation);

    double myGlobalScale = this.getGlobalScale();
    double[][] myGlobalScaleMatrix = MathUtil.scaleMatrix(myGlobalScale);

    double[][] m = MathUtil.getIdentity();
    m = MathUtil.multiply(m, myGlobalTranslationMatrix);
    m = MathUtil.multiply(m, myGlobalRotationMatrix);
    m = MathUtil.multiply(m, myGlobalScaleMatrix);
    return m;
  }
  public double[][] getInverseGlobalMatrix() {
    double[] globalPosition = this.getGlobalPosition();
    double[] inverseTranslation = new double[2];
    inverseTranslation[0] = -globalPosition[0];
    inverseTranslation[1] = -globalPosition[1];
    double[][] myInverseGlobalTranslationMatrix = MathUtil.translationMatrix(inverseTranslation);

    double myInverseRotation = -this.getGlobalRotation();
    double[][] myInverseGlobalRotationMatrix = MathUtil.rotationMatrix(myInverseRotation);

    double myInverseScale = 1d / this.getGlobalScale();
    double[][] myInverseGlobalScaleMatrix = MathUtil.scaleMatrix(myInverseScale);

    double[][] m = MathUtil.getIdentity();
    m = MathUtil.multiply(m, myInverseGlobalScaleMatrix);
    m = MathUtil.multiply(m, myInverseGlobalRotationMatrix);
    m = MathUtil.multiply(m, myInverseGlobalTranslationMatrix);
    return m;
  }
  /**
   * Initialises subbands fields, such as number of code-blocks and code-blocks dimension, in the
   * subband tree. The nominal code-block width/height depends on the precincts dimensions if used.
   *
   * @param t The tile index of the subband
   * @param c The component index
   * @param sb The subband tree to be initialised.
   */
  private void initSubbandsFields(int t, int c, Subband sb) {
    int cbw = cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, t, c);
    int cbh = cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, t, c);

    if (!sb.isNode) {
      // Code-blocks dimension
      int ppx, ppy;
      int ppxExp, ppyExp, cbwExp, cbhExp;
      ppx = pss.getPPX(t, c, sb.resLvl);
      ppy = pss.getPPY(t, c, sb.resLvl);

      if (ppx != Markers.PRECINCT_PARTITION_DEF_SIZE
          || ppy != Markers.PRECINCT_PARTITION_DEF_SIZE) {

        ppxExp = MathUtil.log2(ppx);
        ppyExp = MathUtil.log2(ppy);
        cbwExp = MathUtil.log2(cbw);
        cbhExp = MathUtil.log2(cbh);

        // Precinct partition is used
        switch (sb.resLvl) {
          case 0:
            sb.nomCBlkW = (cbwExp < ppxExp ? (1 << cbwExp) : (1 << ppxExp));
            sb.nomCBlkH = (cbhExp < ppyExp ? (1 << cbhExp) : (1 << ppyExp));
            break;

          default:
            sb.nomCBlkW = (cbwExp < ppxExp - 1 ? (1 << cbwExp) : (1 << (ppxExp - 1)));
            sb.nomCBlkH = (cbhExp < ppyExp - 1 ? (1 << cbhExp) : (1 << (ppyExp - 1)));
            break;
        }
      } else {
        sb.nomCBlkW = cbw;
        sb.nomCBlkH = cbh;
      }

      // Number of code-blocks
      if (sb.numCb == null) sb.numCb = new Point();
      if (sb.w != 0 && sb.h != 0) {
        int acb0x = cb0x;
        int acb0y = cb0y;
        int tmp;

        // Project code-block partition origin to subband. Since the
        // origin is always 0 or 1, it projects to the low-pass side
        // (throught the ceil operator) as itself (i.e. no change) and
        // to the high-pass side (through the floor operator) as 0,
        // always.
        switch (sb.sbandIdx) {
          case Subband.WT_ORIENT_LL:
            // No need to project since all low-pass => nothing to do
            break;
          case Subband.WT_ORIENT_HL:
            acb0x = 0;
            break;
          case Subband.WT_ORIENT_LH:
            acb0y = 0;
            break;
          case Subband.WT_ORIENT_HH:
            acb0x = 0;
            acb0y = 0;
            break;
          default:
            throw new Error("Internal JJ2000 error");
        }
        if (sb.ulcx - acb0x < 0 || sb.ulcy - acb0y < 0) {
          throw new IllegalArgumentException(
              "Invalid code-blocks "
                  + "partition origin or "
                  + "image offset in the "
                  + "reference grid.");
        }
        // NOTE: when calculating "floor()" by integer division the
        // dividend and divisor must be positive, we ensure that by
        // adding the divisor to the dividend and then substracting 1
        // to the result of the division
        tmp = sb.ulcx - acb0x + sb.nomCBlkW;
        sb.numCb.x = (tmp + sb.w - 1) / sb.nomCBlkW - (tmp / sb.nomCBlkW - 1);
        tmp = sb.ulcy - acb0y + sb.nomCBlkH;
        sb.numCb.y = (tmp + sb.h - 1) / sb.nomCBlkH - (tmp / sb.nomCBlkH - 1);
      } else {
        sb.numCb.x = sb.numCb.y = 0;
      }
    } else {
      initSubbandsFields(t, c, sb.getLL());
      initSubbandsFields(t, c, sb.getHL());
      initSubbandsFields(t, c, sb.getLH());
      initSubbandsFields(t, c, sb.getHH());
    }
  }
Beispiel #18
0
 public static <T> T getRandomElement(final T[] collection) {
   if (collection == null || collection.length == 0) {
     return null;
   }
   return collection[MathUtil.randomInteger(collection.length)];
 }
Beispiel #19
0
 public static <T> T getRandomElement(final List<T> collection) {
   if (collection == null || collection.size() == 0) {
     return null;
   }
   return collection.get(MathUtil.randomInteger(collection.size()));
 }
Beispiel #20
0
 public static boolean isLoaded(final org.bukkit.World world, double x, double y, double z) {
   return isLoaded(world, MathUtil.locToChunk(x), MathUtil.locToChunk(z));
 }
Beispiel #21
0
 public static void loadChunks(
     org.bukkit.World world, double xmid, double zmid, final int radius) {
   loadChunks(world, MathUtil.locToChunk(xmid), MathUtil.locToChunk(zmid), radius);
 }
Beispiel #22
0
 /**
  * 1=30度 2=45度 4=60度
  *
  * @return
  */
 public static float switchDegrees(float x, float y) {
   return (float) MathUtil.pointTotoDegrees(x, y);
 }
 /**
  * Evaluate the logit probability of {@link #sumOfProducts(Map)} of values. Probability =
  * exp(logit)/(1+exp(logit)) where logit = sumOfProducts(values) + gamma.
  *
  * @param values set of values with same names as this model. These values are multiplied with the
  *     model's effect estimates (coefficients).
  * @param gamma gamma to add to the sum of products
  * @return logit probability
  */
 public double evaluateLogitProb(Map<String, ? extends Number> values, double gamma) {
   double logit = sumOfProducts(values) + gamma;
   double prob = MathUtil.probFromLogit(logit);
   return prob;
 }
 /**
  * Get the local rotation (in degrees)
  *
  * @return
  */
 public double getRotation() {
   return MathUtil.normaliseAngle(myRotation);
 }
  /**
   * Encodes a packet and returns the buffer containing the encoded packet header. The code-blocks
   * appear in a 3D array of CBlkRateDistStats, 'cbs'. The first index is the tile index in
   * lexicographical order, the second index is the subband index (as defined in the Subband class),
   * and the third index is the code-block index (whithin the subband tile) in lexicographical order
   * as well. The indexes of the new truncation points for each code-block are specified by the 3D
   * array of int 'tIndx'. The indices of this array are the same as for cbs. The truncation point
   * indices in 'tIndx' are the indices of the elements of the 'truncIdxs' array, of the
   * CBlkRateDistStats class, that give the real truncation points. If a truncation point index is
   * negative it means that the code-block has not been included in any layer yet. If the truncation
   * point is less than or equal to the highest truncation point used in previous layers then the
   * code-block is not included in the packet. Otherwise, if larger, the code-block is included in
   * the packet. The body of the packet can be obtained with the getLastBodyBuf() and
   * getLastBodyLen() methods.
   *
   * <p>Layers must be coded in increasing order, in consecutive manner, for each tile, component
   * and resolution level (e.g., layer 1, then layer 2, etc.). For different tile, component and/or
   * resolution level no particular order must be followed.
   *
   * @param ly The layer index (starts at 1).
   * @param c The component index.
   * @param r The resolution level
   * @param t Index of the current tile
   * @param cbs The 3D array of coded code-blocks.
   * @param tIndx The truncation point indices for each code-block.
   * @param hbuf The header buffer. If null a new BitOutputBuffer is created and returned. This
   *     buffer is reset before anything is written to it.
   * @param bbuf The body buffer. If null a new one is created. If not large enough a new one is
   *     created.
   * @param pIdx The precinct index.
   * @return The buffer containing the packet header.
   */
  public BitOutputBuffer encodePacket(
      int ly,
      int c,
      int r,
      int t,
      CBlkRateDistStats cbs[][],
      int tIndx[][],
      BitOutputBuffer hbuf,
      byte bbuf[],
      int pIdx) {
    int b, i, maxi;
    int ncb;
    int thmax;
    int newtp;
    int cblen;
    int prednbits, nbits, deltabits;
    TagTreeEncoder cur_ttIncl, cur_ttMaxBP; // inclusion and bit-depth tag
    // trees
    int cur_prevtIdxs[]; // last encoded truncation points
    CBlkRateDistStats cur_cbs[];
    int cur_tIndx[]; // truncation points to encode
    int minsb = (r == 0) ? 0 : 1;
    int maxsb = (r == 0) ? 1 : 4;
    Point cbCoord = null;
    SubbandAn root = infoSrc.getAnSubbandTree(t, c);
    SubbandAn sb;
    roiInPkt = false;
    roiLen = 0;
    int mend, nend;

    // Checks if a precinct with such an index exists in this resolution
    // level
    if (pIdx >= ppinfo[t][c][r].length) {
      packetWritable = false;
      return hbuf;
    }
    PrecInfo prec = ppinfo[t][c][r][pIdx];

    // First, we check if packet is empty (i.e precinct 'pIdx' has no
    // code-block in any of the subbands)
    boolean isPrecVoid = true;

    for (int s = minsb; s < maxsb; s++) {
      if (prec.nblk[s] == 0) {
        // The precinct has no code-block in this subband.
        continue;
      } else {
        // The precinct is not empty in at least one subband ->
        // stop
        isPrecVoid = false;
        break;
      }
    }

    if (isPrecVoid) {
      packetWritable = true;

      if (hbuf == null) {
        hbuf = new BitOutputBuffer();
      } else {
        hbuf.reset();
      }
      if (bbuf == null) {
        lbbuf = bbuf = new byte[1];
      }
      hbuf.writeBit(0);
      lblen = 0;

      return hbuf;
    }

    if (hbuf == null) {
      hbuf = new BitOutputBuffer();
    } else {
      hbuf.reset();
    }

    // Invalidate last body buffer
    lbbuf = null;
    lblen = 0;

    // Signal that packet is present
    hbuf.writeBit(1);

    for (int s = minsb; s < maxsb; s++) { // Loop on subbands
      sb = (SubbandAn) root.getSubbandByIdx(r, s);

      // Go directly to next subband if the precinct has no code-block
      // in the current one.
      if (prec.nblk[s] == 0) {
        continue;
      }

      cur_ttIncl = ttIncl[t][c][r][pIdx][s];
      cur_ttMaxBP = ttMaxBP[t][c][r][pIdx][s];
      cur_prevtIdxs = prevtIdxs[t][c][r][s];
      cur_cbs = cbs[s];
      cur_tIndx = tIndx[s];

      // Set tag tree values for code-blocks in this precinct
      mend = (prec.cblk[s] == null) ? 0 : prec.cblk[s].length;
      for (int m = 0; m < mend; m++) {
        nend = (prec.cblk[s][m] == null) ? 0 : prec.cblk[s][m].length;
        for (int n = 0; n < nend; n++) {
          cbCoord = prec.cblk[s][m][n].idx;
          b = cbCoord.x + cbCoord.y * sb.numCb.x;

          if (cur_tIndx[b] > cur_prevtIdxs[b] && cur_prevtIdxs[b] < 0) {
            // First inclusion
            cur_ttIncl.setValue(m, n, ly - 1);
          }
          if (ly == 1) { // First layer, need to set the skip of MSBP
            cur_ttMaxBP.setValue(m, n, cur_cbs[b].skipMSBP);
          }
        }
      }

      // Now encode the information
      for (int m = 0; m < prec.cblk[s].length; m++) { // Vertical code-blocks
        for (int n = 0; n < prec.cblk[s][m].length; n++) { // Horiz. cblks
          cbCoord = prec.cblk[s][m][n].idx;
          b = cbCoord.x + cbCoord.y * sb.numCb.x;

          // 1) Inclusion information
          if (cur_tIndx[b] > cur_prevtIdxs[b]) {
            // Code-block included in this layer
            if (cur_prevtIdxs[b] < 0) { // First inclusion
              // Encode layer info
              cur_ttIncl.encode(m, n, ly, hbuf);

              // 2) Max bitdepth info. Encode value
              thmax = cur_cbs[b].skipMSBP + 1;
              for (i = 1; i <= thmax; i++) {
                cur_ttMaxBP.encode(m, n, i, hbuf);
              }

              // Count body size for packet
              lblen += cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
            } else { // Already in previous layer
              // Send "1" bit
              hbuf.writeBit(1);
              // Count body size for packet
              lblen +=
                  cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]]
                      - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
            }

            // 3) Truncation point information
            if (cur_prevtIdxs[b] < 0) {
              newtp = cur_cbs[b].truncIdxs[cur_tIndx[b]];
            } else {
              newtp =
                  cur_cbs[b].truncIdxs[cur_tIndx[b]] - cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] - 1;
            }

            // Mix of switch and if is faster
            switch (newtp) {
              case 0:
                hbuf.writeBit(0); // Send one "0" bit
                break;
              case 1:
                hbuf.writeBits(2, 2); // Send one "1" and one "0"
                break;
              case 2:
              case 3:
              case 4:
                // Send two "1" bits followed by 2 bits
                // representation of newtp-2
                hbuf.writeBits((3 << 2) | (newtp - 2), 4);
                break;
              default:
                if (newtp <= 35) {
                  // Send four "1" bits followed by a five bits
                  // representation of newtp-5
                  hbuf.writeBits((15 << 5) | (newtp - 5), 9);
                } else if (newtp <= 163) {
                  // Send nine "1" bits followed by a seven bits
                  // representation of newtp-36
                  hbuf.writeBits((511 << 7) | (newtp - 36), 16);
                } else {
                  throw new ArithmeticException(
                      "Maximum number " + "of truncation " + "points exceeded");
                }
            }
          } else { // Block not included in this layer
            if (cur_prevtIdxs[b] >= 0) {
              // Already in previous layer. Send "0" bit
              hbuf.writeBit(0);
            } else { // Not in any previous layers
              cur_ttIncl.encode(m, n, ly, hbuf);
            }
            // Go to the next one.
            continue;
          }

          // Code-block length

          // We need to compute the maximum number of bits needed to
          // signal the length of each terminated segment and the
          // final truncation point.
          newtp = 1;
          maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
          cblen =
              (cur_prevtIdxs[b] < 0)
                  ? 0
                  : cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];

          // Loop on truncation points
          i = (cur_prevtIdxs[b] < 0) ? 0 : cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1;
          int minbits = 0;
          for (; i < maxi; i++, newtp++) {
            // If terminated truncation point calculate length
            if (cur_cbs[b].isTermPass != null && cur_cbs[b].isTermPass[i]) {

              // Calculate length
              cblen = cur_cbs[b].truncRates[i] - cblen;

              // Calculate number of needed bits
              prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp);
              minbits = ((cblen > 0) ? MathUtil.log2(cblen) : 0) + 1;

              // Update Lblock increment if needed
              for (int j = prednbits; j < minbits; j++) {
                lblock[t][c][r][s][b]++;
                hbuf.writeBit(1);
              }
              // Initialize for next length
              newtp = 0;
              cblen = cur_cbs[b].truncRates[i];
            }
          }
          // Last truncation point length always sent

          // Calculate length
          cblen = cur_cbs[b].truncRates[i] - cblen;

          // Calculate number of bits
          prednbits = lblock[t][c][r][s][b] + MathUtil.log2(newtp);
          minbits = ((cblen > 0) ? MathUtil.log2(cblen) : 0) + 1;
          // Update Lblock increment if needed
          for (int j = prednbits; j < minbits; j++) {
            lblock[t][c][r][s][b]++;
            hbuf.writeBit(1);
          }

          // End of comma-code increment
          hbuf.writeBit(0);

          // There can be terminated several segments, send length
          // info for all terminated truncation points in addition
          // to final one
          newtp = 1;
          maxi = cur_cbs[b].truncIdxs[cur_tIndx[b]];
          cblen =
              (cur_prevtIdxs[b] < 0)
                  ? 0
                  : cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
          // Loop on truncation points and count the groups
          i = (cur_prevtIdxs[b] < 0) ? 0 : cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] + 1;
          for (; i < maxi; i++, newtp++) {
            // If terminated truncation point, send length
            if (cur_cbs[b].isTermPass != null && cur_cbs[b].isTermPass[i]) {

              cblen = cur_cbs[b].truncRates[i] - cblen;
              nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b];
              hbuf.writeBits(cblen, nbits);

              // Initialize for next length
              newtp = 0;
              cblen = cur_cbs[b].truncRates[i];
            }
          }
          // Last truncation point length is always signalled
          // First calculate number of bits needed to signal
          // Calculate length
          cblen = cur_cbs[b].truncRates[i] - cblen;
          nbits = MathUtil.log2(newtp) + lblock[t][c][r][s][b];
          hbuf.writeBits(cblen, nbits);
        } // End loop on horizontal code-blocks
      } // End loop on vertical code-blocks
    } // End loop on subband

    // -> Copy the data to the body buffer

    // Ensure size for body data
    if (bbuf == null || bbuf.length < lblen) {
      bbuf = new byte[lblen];
    }
    lbbuf = bbuf;
    lblen = 0;

    for (int s = minsb; s < maxsb; s++) { // Loop on subbands
      sb = (SubbandAn) root.getSubbandByIdx(r, s);

      cur_prevtIdxs = prevtIdxs[t][c][r][s];
      cur_cbs = cbs[s];
      cur_tIndx = tIndx[s];
      ncb = cur_prevtIdxs.length;

      mend = (prec.cblk[s] == null) ? 0 : prec.cblk[s].length;
      for (int m = 0; m < mend; m++) { // Vertical code-blocks
        nend = (prec.cblk[s][m] == null) ? 0 : prec.cblk[s][m].length;
        for (int n = 0; n < nend; n++) { // Horiz. cblks
          cbCoord = prec.cblk[s][m][n].idx;
          b = cbCoord.x + cbCoord.y * sb.numCb.x;

          if (cur_tIndx[b] > cur_prevtIdxs[b]) {

            // Block included in this precinct -> Copy data to
            // body buffer and get code-size
            if (cur_prevtIdxs[b] < 0) {
              cblen = cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]];
              System.arraycopy(cur_cbs[b].data, 0, lbbuf, lblen, cblen);
            } else {
              cblen =
                  cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_tIndx[b]]]
                      - cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]];
              System.arraycopy(
                  cur_cbs[b].data,
                  cur_cbs[b].truncRates[cur_cbs[b].truncIdxs[cur_prevtIdxs[b]]],
                  lbbuf,
                  lblen,
                  cblen);
            }
            lblen += cblen;

            // Verifies if this code-block contains new ROI
            // information
            if (cur_cbs[b].nROIcoeff != 0
                && (cur_prevtIdxs[b] == -1
                    || cur_cbs[b].truncIdxs[cur_prevtIdxs[b]] <= cur_cbs[b].nROIcp - 1)) {
              roiInPkt = true;
              roiLen = lblen;
            }

            // Update truncation point
            cur_prevtIdxs[b] = cur_tIndx[b];
          }
        } // End loop on horizontal code-blocks
      } // End loop on vertical code-blocks
    } // End loop on subbands

    packetWritable = true;

    // Must never happen
    if (hbuf.getLength() == 0) {
      throw new Error("You have found a bug in PktEncoder, method:" + " encodePacket");
    }

    return hbuf;
  }