// Path: src/main/java/com/codegame/codeseries/notreal2d/form/Form.java
// public abstract class Form {
//     @Nonnull
//     private final Shape shape;
// 
//     protected Form(@Nonnull Shape shape) {
//         Preconditions.checkNotNull(shape, "Argument 'shape' is null.");
// 
//         this.shape = shape;
//     }
// 
//     @Nonnull
//     public Shape getShape() {
//         return shape;
//     }
// 
//     public abstract double getCircumcircleRadius();
// 
//     @Nonnull
//     public abstract Point2D getCenterOfMass(@Nonnull Point2D position, double angle);
// 
//     @Nonnull
//     public final Point2D getCenterOfMass(@Nonnull Body body) {
//         return getCenterOfMass(body.getPosition(), body.getAngle());
//     }
// 
//     public abstract double getAngularMass(double mass);
// 
//     @Override
//     public abstract String toString();
// 
//     @Nonnull
//     public static String toString(@Nullable Form form) {
//         return form == null ? "Form {null}" : form.toString();
//     }
// 
//     @Contract(pure = true)
//     protected static double normalizeSinCos(double value, double epsilon) {
//         return abs(value) < epsilon ? 0.0D
//                 : abs(1.0D - value) < epsilon ? 1.0D
//                 : abs(-1.0D - value) < epsilon ? -1.0D
//                 : value;
//     }
// }
// 
// Path: src/main/java/com/codegame/codeseries/notreal2d/provider/ConstantMovementFrictionProvider.java
// public class ConstantMovementFrictionProvider implements MovementFrictionProvider {
//     private final double movementFrictionFactor;
// 
//     public ConstantMovementFrictionProvider(double movementFrictionFactor) {
//         if (movementFrictionFactor < 0.0D) {
//             throw new IllegalArgumentException("Argument 'movementFrictionFactor' should be zero or positive.");
//         }
// 
//         this.movementFrictionFactor = movementFrictionFactor;
//     }
// 
//     public double getMovementFrictionFactor() {
//         return movementFrictionFactor;
//     }
// 
//     @Override
//     public void applyFriction(Body body, double updateFactor) {
//         if (movementFrictionFactor <= 0.0D) {
//             return;
//         }
// 
//         double velocityLength = body.getVelocity().getLength();
//         if (velocityLength <= 0.0D) {
//             return;
//         }
// 
//         double velocityChange = movementFrictionFactor * updateFactor;
// 
//         if (velocityChange >= velocityLength) {
//             body.setVelocity(0.0D, 0.0D);
//         } else if (velocityChange > 0.0D) {
//             body.getVelocity().multiply(1.0D - velocityChange / velocityLength);
//         }
//     }
// }
// 
// Path: src/main/java/com/codegame/codeseries/notreal2d/provider/MovementFrictionProvider.java
// public interface MovementFrictionProvider {
//     void applyFriction(Body body, double updateFactor);
// }


import com.codeforces.commons.geometry.Point2D;
import com.codeforces.commons.geometry.Vector2D;
import com.codeforces.commons.text.StringUtil;
import com.codegame.codeseries.notreal2d.form.Form;
import com.codegame.codeseries.notreal2d.provider.ConstantMovementFrictionProvider;
import com.codegame.codeseries.notreal2d.provider.MovementFrictionProvider;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import static com.codeforces.commons.math.Math.pow;

package com.codegame.codeseries.notreal2d;




/**
 * @author Maxim Shipko (sladethe@gmail.com)
 *         Date: 02.06.2015
 */
public class Body {
    private static final AtomicLong idGenerator = new AtomicLong();

    /**
     * Unique ID.
     */
    private final long id = idGenerator.incrementAndGet();

    /**
     * The name of this body.
     */
    private String name;

    /**
     * The form (shape and size) of this body.
     */
    private Form form;

    /**
     * The mass of this body.
     */
    private double mass;

    /**
     * The inverted mass of this body. Used to speed up some calculations.
     */
    private double invertedMass;

    /**
     * The relative loss of the speed per time unit. Should be in range [0, 1].
     */
    private double movementAirFrictionFactor;

    /**
     * The relative loss of the angular speed per time unit. Should be in range [0, 1].
     */
    private double rotationAirFrictionFactor;

    /**
     * The provider of the absolute loss of the speed.
     */

// Path: src/main/java/com/codegame/codeseries/notreal2d/form/Form.java
// public abstract class Form {
//     @Nonnull
//     private final Shape shape;
// 
//     protected Form(@Nonnull Shape shape) {
//         Preconditions.checkNotNull(shape, "Argument 'shape' is null.");
// 
//         this.shape = shape;
//     }
// 
//     @Nonnull
//     public Shape getShape() {
//         return shape;
//     }
// 
//     public abstract double getCircumcircleRadius();
// 
//     @Nonnull
//     public abstract Point2D getCenterOfMass(@Nonnull Point2D position, double angle);
// 
//     @Nonnull
//     public final Point2D getCenterOfMass(@Nonnull Body body) {
//         return getCenterOfMass(body.getPosition(), body.getAngle());
//     }
// 
//     public abstract double getAngularMass(double mass);
// 
//     @Override
//     public abstract String toString();
// 
//     @Nonnull
//     public static String toString(@Nullable Form form) {
//         return form == null ? "Form {null}" : form.toString();
//     }
// 
//     @Contract(pure = true)
//     protected static double normalizeSinCos(double value, double epsilon) {
//         return abs(value) < epsilon ? 0.0D
//                 : abs(1.0D - value) < epsilon ? 1.0D
//                 : abs(-1.0D - value) < epsilon ? -1.0D
//                 : value;
//     }
// }
// 
// Path: src/main/java/com/codegame/codeseries/notreal2d/provider/ConstantMovementFrictionProvider.java
// public class ConstantMovementFrictionProvider implements MovementFrictionProvider {
//     private final double movementFrictionFactor;
// 
//     public ConstantMovementFrictionProvider(double movementFrictionFactor) {
//         if (movementFrictionFactor < 0.0D) {
//             throw new IllegalArgumentException("Argument 'movementFrictionFactor' should be zero or positive.");
//         }
// 
//         this.movementFrictionFactor = movementFrictionFactor;
//     }
// 
//     public double getMovementFrictionFactor() {
//         return movementFrictionFactor;
//     }
// 
//     @Override
//     public void applyFriction(Body body, double updateFactor) {
//         if (movementFrictionFactor <= 0.0D) {
//             return;
//         }
// 
//         double velocityLength = body.getVelocity().getLength();
//         if (velocityLength <= 0.0D) {
//             return;
//         }
// 
//         double velocityChange = movementFrictionFactor * updateFactor;
// 
//         if (velocityChange >= velocityLength) {
//             body.setVelocity(0.0D, 0.0D);
//         } else if (velocityChange > 0.0D) {
//             body.getVelocity().multiply(1.0D - velocityChange / velocityLength);
//         }
//     }
// }
// 
// Path: src/main/java/com/codegame/codeseries/notreal2d/provider/MovementFrictionProvider.java
// public interface MovementFrictionProvider {
//     void applyFriction(Body body, double updateFactor);
// }


// Path: src/main/java/com/codegame/codeseries/notreal2d/Body.java
import com.codeforces.commons.geometry.Point2D;
import com.codeforces.commons.geometry.Vector2D;
import com.codeforces.commons.text.StringUtil;
import com.codegame.codeseries.notreal2d.form.Form;
import com.codegame.codeseries.notreal2d.provider.ConstantMovementFrictionProvider;
import com.codegame.codeseries.notreal2d.provider.MovementFrictionProvider;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import static com.codeforces.commons.math.Math.pow;

package com.codegame.codeseries.notreal2d;




/**
 * @author Maxim Shipko (sladethe@gmail.com)
 *         Date: 02.06.2015
 */
public class Body {
    private static final AtomicLong idGenerator = new AtomicLong();

    /**
     * Unique ID.
     */
    private final long id = idGenerator.incrementAndGet();

    /**
     * The name of this body.
     */
    private String name;

    /**
     * The form (shape and size) of this body.
     */
    private Form form;

    /**
     * The mass of this body.
     */
    private double mass;

    /**
     * The inverted mass of this body. Used to speed up some calculations.
     */
    private double invertedMass;

    /**
     * The relative loss of the speed per time unit. Should be in range [0, 1].
     */
    private double movementAirFrictionFactor;

    /**
     * The relative loss of the angular speed per time unit. Should be in range [0, 1].
     */
    private double rotationAirFrictionFactor;

    /**
     * The provider of the absolute loss of the speed.
     */

    private MovementFrictionProvider movementFrictionProvider = new ConstantMovementFrictionProvider(0.0D);
