/** Test against perfectly matched and a little bit of noise */
  @Test
  public void test2D() {
    for (double noise = 0; noise <= 0.01; noise += 0.01) {
      // can only correct small changes
      Se2_F64 tran = new Se2_F64(0.01, -0.02, 0.01);

      List<Point2D_F64> srcPts = UtilPoint2D_F64.random(-10, 10, 30, rand);
      List<Point2D_F64> srcOrig = UtilPoint2D_F64.copy(srcPts);
      List<Point2D_F64> modelPts = new ArrayList<Point2D_F64>();
      for (Point2D_F64 p : srcPts) {
        modelPts.add(SePointOps_F64.transform(tran, p, null));
      }

      // add noise
      UtilPoint2D_F64.noiseNormal(modelPts, noise, rand);

      PointModel<Point2D_F64> model = new PointModel<Point2D_F64>(modelPts);
      StoppingCondition stop = new StoppingCondition(10, 0.1 * noise / srcPts.size() + 1e-8);
      IterativeClosestPoint<Se2_F64, Point2D_F64> alg =
          new IterativeClosestPoint<Se2_F64, Point2D_F64>(stop, new MotionSe2PointSVD_F64());
      alg.setModel(model);

      alg.process(srcPts);

      Se2_F64 foundTran = alg.getPointsToModel();

      checkTransform(srcOrig, modelPts, foundTran, noise * 10 + 1e-8);
    }
  }
  /**
   * Returns the closest point on the contour to the provided point in space
   *
   * @return index of closest point
   */
  int closestPoint(Point2D_F64 target) {
    double bestDistance = Double.MAX_VALUE;
    int bestIndex = -1;
    for (int i = 0; i < contour.size(); i++) {
      Point2D_I32 c = contour.get(i);

      double d = UtilPoint2D_F64.distanceSq(target.x, target.y, c.x, c.y);
      if (d < bestDistance) {
        bestDistance = d;
        bestIndex = i;
      }
    }
    return bestIndex;
  }
  @Test
  public void noiseless() {
    Affine2D_F64 tran = new Affine2D_F64(2, -4, 0.3, 1.1, 0.93, -3);

    List<Point2D_F64> from = UtilPoint2D_F64.random(-10, 10, 30, rand);
    List<Point2D_F64> to = new ArrayList<Point2D_F64>();
    for (Point2D_F64 p : from) {
      to.add(AffinePointOps.transform(tran, p, null));
    }

    MotionAffinePoint2D_F64 alg = new MotionAffinePoint2D_F64();

    assertTrue(alg.process(from, to));

    Affine2D_F64 tranFound = alg.getMotion();

    checkTransform(from, to, tranFound, GrlConstants.DOUBLE_TEST_TOL);
  }