private double[][] getShadowSmoothKernel(int radius) {
    double res[][] = shadowSmoothKernelMap.get(Integer.valueOf(radius));
    if (res == null) {
      FilterKernel shadowSmoothKernel = new GaussianFilterKernel();
      double shadowKernelScale = 1.0;
      double shadowScaledInvRadius =
          1.0 / shadowSmoothRadius * shadowKernelScale * shadowSmoothKernel.getSpatialSupport();

      int size = 2 * radius + 1;
      res = new double[size][size];

      for (int k = -radius; k <= radius; k++) {
        int x = radius + k;
        double k_square = MathLib.sqr(k * shadowScaledInvRadius);
        for (int l = -radius; l <= radius; l++) {
          int y = radius + l;
          double r = MathLib.sqrt(k_square + MathLib.sqr(l * shadowScaledInvRadius));
          res[x][y] = shadowSmoothKernel.getFilterCoeff(r);
        }
      }

      synchronized (shadowSmoothKernelMap) {
        shadowSmoothKernelMap.put(Integer.valueOf(radius), res);
      }
    }

    return res;
  }
  private void computeNextTimeStep(float t, float dt) {
    for (Particle particle : particles) {
      Vector force = getForce(t);
      particle.incSpeed(VectorMath.multiply(dt, force));

      float radialAccel = particle.getRadialAcceleration() * dt;
      float tangentAccel = particle.getTangentialAcceleration() * dt;
      if (MathLib.fabs(radialAccel) > MathLib.EPSILON
          || MathLib.fabs(tangentAccel) > MathLib.EPSILON) {
        Vector centre = getForceCentre(t);
        Vector normal = VectorMath.normalize(VectorMath.normal(particle.getPosition(), centre));
        if (MathLib.fabs(radialAccel) > MathLib.EPSILON) {
          particle.incSpeed(VectorMath.multiply(radialAccel, normal));
        }
        if (MathLib.fabs(tangentAccel) > MathLib.EPSILON) {
          Vector tangent = VectorMath.normalize(VectorMath.tangent(particle.getPosition(), centre));
          particle.incSpeed(VectorMath.multiply(tangentAccel, tangent));
        }
      }

      particle.incPosition(VectorMath.multiply(dt, particle.getSpeed()));
      particle.incRotation(VectorMath.multiply(dt, particle.getRotationSpeed()));

      particle.decLife(dt);
    }
    storeMotion(t, dt);
  }
 protected int selectNearestPointFromTriangle(
     TriangleControlShape pTriangle, int viewX, int viewY) {
   double dx, dy;
   dx = pTriangle.viewX[0] - viewX;
   dy = pTriangle.viewY[0] - viewY;
   double dr0 = MathLib.sqrt(dx * dx + dy * dy);
   dx = pTriangle.viewX[1] - viewX;
   dy = pTriangle.viewY[1] - viewY;
   double dr1 = MathLib.sqrt(dx * dx + dy * dy);
   dx = pTriangle.viewX[2] - viewX;
   dy = pTriangle.viewY[2] - viewY;
   double dr2 = MathLib.sqrt(dx * dx + dy * dy);
   return dr0 < dr1 ? (dr0 < dr2 ? 0 : 2) : (dr1 < dr2 ? 1 : 2);
 }