@SuppressWarnings("OverlyLongMethod")
  @Nullable
  @Override
  protected CollisionInfo collideOneWay(@Nonnull Body bodyA, @Nonnull Body bodyB) {
    RectangularForm rectangularFormA = (RectangularForm) bodyA.getForm();
    CircularForm circularFormB = (CircularForm) bodyB.getForm();

    Point2D[] pointsA = rectangularFormA.getPoints(bodyA.getPosition(), bodyA.getAngle(), epsilon);
    int pointACount = pointsA.length;

    if (!GeometryUtil.isPointOutsideConvexPolygon(bodyB.getPosition(), pointsA, epsilon)) {
      double minDistanceFromB = Double.POSITIVE_INFINITY;
      Line2D nearestLineA = null;

      for (int pointAIndex = 0; pointAIndex < pointACount; ++pointAIndex) {
        Point2D point1A = pointsA[pointAIndex];
        Point2D point2A = pointsA[pointAIndex == pointACount - 1 ? 0 : pointAIndex + 1];

        Line2D lineA = Line2D.getLineByTwoPoints(point1A, point2A);
        double distanceFromB = lineA.getDistanceFrom(bodyB.getPosition());

        if (distanceFromB < minDistanceFromB) {
          minDistanceFromB = distanceFromB;
          nearestLineA = lineA;
        }
      }

      if (nearestLineA != null) {
        return new CollisionInfo(
            bodyA,
            bodyB,
            bodyB.getPosition(),
            nearestLineA.getUnitNormal().negate(),
            circularFormB.getRadius() - nearestLineA.getSignedDistanceFrom(bodyB.getPosition()),
            epsilon);
      }
    }

    CollisionInfo collisionInfo = null;

    for (int pointAIndex = 0; pointAIndex < pointACount; ++pointAIndex) {
      Point2D point1A = pointsA[pointAIndex];
      Point2D point2A = pointsA[pointAIndex == pointACount - 1 ? 0 : pointAIndex + 1];

      CollisionInfo lineCollisionInfo =
          LineAndCircleCollider.collideOneWay(
              bodyA, bodyB, point1A, point2A, circularFormB, epsilon);

      if (lineCollisionInfo != null
          && (collisionInfo == null || lineCollisionInfo.getDepth() > collisionInfo.getDepth())) {
        collisionInfo = lineCollisionInfo;
      }
    }

    return collisionInfo;
  }
 @Override
 protected boolean matchesOneWay(@Nonnull Body bodyA, @Nonnull Body bodyB) {
   return bodyA.getForm().getShape() == Shape.RECTANGLE
       && bodyB.getForm().getShape() == Shape.CIRCLE;
 }