package sim.physics2D.physicalObject; import sim.physics2D.util.*; import sim.physics2D.shape.*; import sim.util.Double2D; /** * MobileObject2D represents a physical object that can move. */ public abstract class MobileObject2D extends PhysicalObject2D { protected double coefficientOfFriction; protected double coefficientOfStaticFriction; protected double mass = 0; protected double massMomentOfInertia = 0; private static final double zeroVelocity = 0.01; private double normalForce; private static final double gravity = .1; public MobileObject2D() { this.setPose(new Double2D(0,0), new Angle(0)); this.setVelocity(new Double2D(0,0)); this.setAngularVelocity(0); } /** Returns the object's mass */ public double getMass() { return mass; } /** Sets an object's mass. The mass moment of inertia is calculated * by the object's associated shape */ public void setMass(double mass) { massMomentOfInertia = shape.getMassMomentOfInertia(mass); double massMomentOfInertiaInverse; if (massMomentOfInertia > 0) massMomentOfInertiaInverse = 1 / this.massMomentOfInertia; else massMomentOfInertiaInverse = 0; // Precompute inverses since we need them a lot in collision response double massInverse = 1 / mass; physicsState.setMassInverse(massInverse, massMomentOfInertiaInverse, index); this.mass = mass; normalForce = mass * gravity; } /** Apply a force to the MobileObject */ public void addForce(Double2D force) { physicsState.addExternalForce(force, this.index); } /** Apply a torque to the MobileObject */ public void addTorque(double torque) { physicsState.addExternalTorque(torque, this.index); } /** Positive value representing the coefficient of friction of the * object with the background surface. 0 is no friction */ public double getCoefficientOfFriction() { return coefficientOfFriction; } /** Positive value representing the coefficient of friction of the * object with the background surface. 0 is no friction */ public void setCoefficientOfFriction(double coefficientOfFriction) { this.coefficientOfFriction = coefficientOfFriction; } /** Positive value representing the coefficient of static friction of the * object with the background surface. 0 is no static friction */ public double getCoefficientOfStaticFriction() { return coefficientOfStaticFriction; } /** Positive value representing the coefficient of static friction of the * object with the background surface. 0 is no static friction */ public void setCoefficientOfStaticFriction(double coefficientOfStaticFriction) { this.coefficientOfStaticFriction = coefficientOfStaticFriction; } /** Set the shape of the object which determines how it is displayed, * when it is colliding with another object, and how its mass moment of * inertia is calculated */ public void setShape(Shape shape, double mass) { this.shape = shape; this.shape.setIndex(this.index); this.shape.calcMaxDistances(true); setMass(mass); } /** Updates the pose to where the object would be in only a percentage * of a time step. Useful for searching for exact moment of collision. */ public void updatePose(double percent) { this.setPose(this.getPosition().add(physicsState.getLastVelocity(this.index).multiply(percent)), this.getOrientation().add(physicsState.getLastAngularVelocity(this.index))); } /** Move the object back to its previous location */ public void resetLastPose() { this.setPose(physicsState.getLastPosition(this.index), physicsState.getLastOrientation(this.index)); } /** Restores an object to its current location */ public void restorePose() { this.setPose(physicsState.getSavedPosition(this.index), physicsState.getSavedOrientation(this.index)); } /** Returns the object's velocity */ public Double2D getVelocity() { return physicsState.getVelocity(index); } /** Updates the object's velocity */ public void setVelocity(Double2D velocity) { physicsState.setVelocity(velocity, index); } /** How fast the object is rotating in radians per second. * A positive angular velocity means the object is rotating * counter clockwise */ public double getAngularVelocity() { return physicsState.getAngularVelocity(index); } /** How fast the object is rotating in radians per second. * A positive angular velocity means the object is rotating * counter clockwise */ public void setAngularVelocity(double angularVelocity) { physicsState.setAngularVelocity(angularVelocity, index); } /** Returns a vector that represents a combination of * all the forces applied to it */ public Double2D getForceAccumulator() { return physicsState.getExternalForce(index); } /** Returns a number that represents a combination of * all the torques applied to it */ public double getTorqueAccumulator() { return physicsState.getExternalTorque(index); } /** 1 / mass. Used in collision response */ public double getMassInverse() { return physicsState.getMassInverse(index); } /** 1 / massMomentOfInertia. Used in collision response */ public double getMassMomentOfInertiaInverse() { return physicsState.getMassMomentOfInertiaInverse(index); } /** Calculates and adds the static and dynamic friction forces on the object * based on the coefficients of friction. */ public void addFrictionForce() { if (this.coefficientOfFriction > 0 || this.coefficientOfStaticFriction > 0) { Double2D velocity = this.getVelocity(); double velLength = velocity.length(); if (velLength < zeroVelocity) { // static friction Double2D externalForce = this.getForceAccumulator(); if (normalForce * this.getCoefficientOfStaticFriction() > externalForce.length()) this.addForce(new Double2D(-externalForce.x, -externalForce.y)); } // add dynamic friction if (velLength > 0) { Double2D velRot = new Double2D(-velocity.x, -velocity.y); this.addForce(velRot.multiply(this.getCoefficientOfFriction() * normalForce)); } } } }