package zenproject.meditation.android.sketch.painting.flowers.branch; import com.juankysoriano.rainbow.core.matrix.RVector; import com.juankysoriano.rainbow.utils.RainbowMath; import zenproject.meditation.android.ContextRetriever; import zenproject.meditation.android.R; /** * TODO * This class could be much better written, attention to the constructors. * We could avoid writing so many sh*t there. */ public class Branch { private static final float MIN_RADIUS = ContextRetriever.INSTANCE.getResources().getDimension(R.dimen.branch_min_radius); private static final float MIN_RADIUS_TO_BLOOM = ContextRetriever.INSTANCE.getResources().getDimension(R.dimen.branch_min_bloom_radius); private static final float DEFAULT_RADIUS = ContextRetriever.INSTANCE.getResources().getDimension(R.dimen.branch_default_radius); private static final float MIN_STEP = 0.05f; private static final float MAX_STEP = 0.25f; private static final float MIN_RADIUS_FACTOR = 0.9f; private static final float MAX_RADIUS_FACTOR = 1.1f; private static final float SHRINK = RainbowMath.random(0.94f, 0.96f); private float angle; private float radius; private RVector position; private final RVector previousPosition; private final float step; protected Branch(RVector position, float angle, float radius, float step) { this.position = new RVector(position.x, position.y); this.previousPosition = new RVector(this.position.x, this.position.y); this.angle = angle; this.step = step; this.radius = radius * RainbowMath.random(MIN_RADIUS_FACTOR, MAX_RADIUS_FACTOR); } private static float generateRandomStep(Branch branch) { float randomStep = RainbowMath.random(MIN_STEP, MAX_STEP); return branch.step >= 0 ? -randomStep : randomStep; } public static Branch createFrom(Branch branch) { return new Branch(branch.position, branch.angle, branch.radius, generateRandomStep(branch)); } public static Branch createAt(float x, float y) { float angle = RainbowMath.random(-RainbowMath.PI, RainbowMath.PI); RVector pos = new RVector(x, y); return new Branch(pos, angle, DEFAULT_RADIUS, 0); } public boolean isDead() { return RainbowMath.abs(radius) < MIN_RADIUS; } public boolean canBloom() { return RainbowMath.abs(radius) > MIN_RADIUS_TO_BLOOM; } public void update() { backupPosition(); updatePosition(); updateAngle(); updateRadius(); } private void backupPosition() { previousPosition.x = position.x; previousPosition.y = position.y; } private void updatePosition() { position.x += radius * RainbowMath.cos(angle); position.y += radius * RainbowMath.sin(angle); } private void updateAngle() { angle += step; } private void updateRadius() { radius *= SHRINK; } public float getX() { return position.x; } public float getY() { return position.y; } public float getOldX() { return previousPosition.x; } public float getOldY() { return previousPosition.y; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Branch)) { return false; } Branch branch = (Branch) o; return previousPosition.equals(branch.previousPosition) && position.equals(branch.position); } @Override public int hashCode() { int result = position.hashCode(); result = 31 * result + previousPosition.hashCode(); return result; } }