content: package io.codetail.animation.arcanimator;
  
  
  import android.graphics.PointF;
  
  import java.util.Arrays;
  
  class ArcMetric {
  
      PointF mStartPoint = new PointF();
  
      PointF mEndPoint = new PointF();
  
      PointF mMidPoint = new PointF();
  
      PointF mAxisPoint[] = new PointF[2];
  
      PointF mZeroPoint = new PointF();
  
      //SEGMENTS. This Segments create virtual triangle except mZeroStartSegment
  
      float mStartEndSegment;
  
      float mRadius;
  
      float mMidAxisSegment;
  
      float mZeroStartSegment;
  
      //DEGREES.
  
      float mAnimationDegree;
  
      float mSideDegree;
  
      float mZeroStartDegree;
  
      float mStartDegree;
  
      float mEndDegree;
  
      //Side of animation
      Side mSide;
  
      private void createAxisVariables(){
          for(int i=0; i<mAxisPoint.length; i++)
              mAxisPoint[i] = new PointF();
      }
  
  
      private void calcStartEndSeg(){
          mStartEndSegment = (float) Math.sqrt(Math.pow(mStartPoint.x - mEndPoint.x, 2)+
                  Math.pow(mStartPoint.y - mEndPoint.y, 2));
  
      }
  
      private void calcRadius(){
          mSideDegree = (180 - mAnimationDegree)/2;
          mRadius = mStartEndSegment/Utils.sin(mAnimationDegree)*Utils.sin(mSideDegree);
      }
  
      private void calcMidAxisSeg(){
          mMidAxisSegment = mRadius * Utils.sin(mSideDegree);
      }
  
      private void calcMidPoint(){
          mMidPoint.x = mStartPoint.x + mStartEndSegment/2*(mEndPoint.x - mStartPoint.x)/mStartEndSegment;
          mMidPoint.y = mStartPoint.y + mStartEndSegment/2*(mEndPoint.y - mStartPoint.y)/mStartEndSegment;
      }
  
      private void calcAxisPoints(){
          if(mStartPoint.y > mEndPoint.y || mStartPoint.y == mEndPoint.y){
              mAxisPoint[0].x = mMidPoint.x + mMidAxisSegment*(mEndPoint.y-mStartPoint.y)/mStartEndSegment;
              mAxisPoint[0].y = mMidPoint.y - mMidAxisSegment*(mEndPoint.x-mStartPoint.x)/mStartEndSegment;
  
              mAxisPoint[1].x = mMidPoint.x - mMidAxisSegment*(mEndPoint.y-mStartPoint.y)/mStartEndSegment;
              mAxisPoint[1].y = mMidPoint.y + mMidAxisSegment*(mEndPoint.x-mStartPoint.x)/mStartEndSegment;
          }else{
              mAxisPoint[0].x = mMidPoint.x - mMidAxisSegment*(mEndPoint.y-mStartPoint.y)/mStartEndSegment;
              mAxisPoint[0].y = mMidPoint.y + mMidAxisSegment*(mEndPoint.x-mStartPoint.x)/mStartEndSegment;
  
              mAxisPoint[1].x = mMidPoint.x + mMidAxisSegment*(mEndPoint.y-mStartPoint.y)/mStartEndSegment;
              mAxisPoint[1].y = mMidPoint.y - mMidAxisSegment*(mEndPoint.x-mStartPoint.x)/mStartEndSegment;
          }
      }
  
      private void calcZeroPoint(){
          switch (mSide){
              case RIGHT:
                  mZeroPoint.x = mAxisPoint[Side.RIGHT.value].x + mRadius;
                  mZeroPoint.y = mAxisPoint[Side.RIGHT.value].y;
                  break;
              case LEFT:
                  mZeroPoint.x = mAxisPoint[Side.LEFT.value].x - mRadius;
                  mZeroPoint.y = mAxisPoint[Side.LEFT.value].y;
                  break;
          }
      }
  
      private void calcDegrees(){
          mZeroStartSegment = (float) Math.sqrt(Math.pow(mZeroPoint.x - mStartPoint.x, 2)+
                  Math.pow(mZeroPoint.y - mStartPoint.y, 2));
          mZeroStartDegree = Utils.acos((2*Math.pow(mRadius,2)-Math.pow(mZeroStartSegment,2))/(2*Math.pow(mRadius,2)));
          switch(mSide){
              case RIGHT:
                  if(mStartPoint.y <= mZeroPoint.y){
                      if(mStartPoint.y > mEndPoint.y ||
                              (mStartPoint.y == mEndPoint.y && mStartPoint.x > mEndPoint.x)){
                          mStartDegree = mZeroStartDegree;
                          mEndDegree = mStartDegree + mAnimationDegree;
                      }else{
                          mStartDegree = mZeroStartDegree;
                          mEndDegree = mStartDegree - mAnimationDegree;
                      }
                  }else if(mStartPoint.y >= mZeroPoint.y){
                      if(mStartPoint.y < mEndPoint.y ||
                              (mStartPoint.y == mEndPoint.y && mStartPoint.x > mEndPoint.x)){
                          mStartDegree = 0 - mZeroStartDegree;
                          mEndDegree = mStartDegree - mAnimationDegree;
                      }else {
                          mStartDegree = 0 - mZeroStartDegree;
                          mEndDegree = mStartDegree + mAnimationDegree;
                      }
                  }
                  break;
              case LEFT:
                  if(mStartPoint.y <= mZeroPoint.y){
                      if(mStartPoint.y > mEndPoint.y ||
                              (mStartPoint.y == mEndPoint.y && mStartPoint.x < mEndPoint.x)){
                          mStartDegree = 180 - mZeroStartDegree;
                          mEndDegree = mStartDegree - mAnimationDegree;
                      }else{
                          mStartDegree = 180 - mZeroStartDegree;
                          mEndDegree = mStartDegree + mAnimationDegree;
                      }
                  }else if(mStartPoint.y >= mZeroPoint.y){
                      if(mStartPoint.y < mEndPoint.y ||
                              (mStartPoint.y == mEndPoint.y && mStartPoint.x < mEndPoint.x)){
                          mStartDegree = 180 + mZeroStartDegree;
                          mEndDegree = mStartDegree + mAnimationDegree;
                      }else{
                          mStartDegree = 180 + mZeroStartDegree;
                          mEndDegree = mStartDegree - mAnimationDegree;
                      }
                  }
                  break;
          }
      }
  
      /**
       * Create new {@link ArcMetric} instance and do all calculations below
       * and finally return ready to use object
       */
      public static ArcMetric evaluate(float startX, float startY,
                                         float endX, float endY,
                                         float degree, Side side){
          //TODO return ready to use object with have done computations
          ArcMetric arcMetric = new ArcMetric();
          arcMetric.mStartPoint.set(startX, startY);
          arcMetric.mEndPoint.set(endX, endY);
          arcMetric.setDegree(degree);
          arcMetric.mSide = side;
          arcMetric.createAxisVariables();
  
          arcMetric.calcStartEndSeg();
          arcMetric.calcRadius();
          arcMetric.calcMidAxisSeg();
          arcMetric.calcMidPoint();
          arcMetric.calcAxisPoints();
          arcMetric.calcZeroPoint();
          arcMetric.calcDegrees();
  
          return arcMetric;
      }
  
      public void setDegree(float degree) {
          degree = Math.abs(degree);
          if(degree>180)
              setDegree(degree%180);
          else if(degree == 180)
              setDegree(degree-1);
          else if(degree<30)
              setDegree(30);
          else
              this.mAnimationDegree = degree;
      }
  
      PointF getAxisPoint(){
          return mAxisPoint[mSide.value];
      }
  
      /**
       * Return evaluated start degree
       *
       * @return the start degree
       */
      public float getStartDegree(){
          return mStartDegree;
      }
  
      /**
       * Return evaluated end degree
       *
       * @return the end degree
       */
      public float getEndDegree(){
          return mEndDegree;
      }
  
      @Override
      public String toString() {
          return "ArcMetric{" +
                  "\nmStartPoint=" + mStartPoint +
                  "\n mEndPoint=" + mEndPoint +
                  "\n mMidPoint=" + mMidPoint +
                  "\n mAxisPoint=" + Arrays.toString(mAxisPoint) +
                  "\n mZeroPoint=" + mZeroPoint +
                  "\n mStartEndSegment=" + mStartEndSegment +
                  "\n mRadius=" + mRadius +
                  "\n mMidAxisSegment=" + mMidAxisSegment +
                  "\n mZeroStartSegment=" + mZeroStartSegment +
                  "\n mAnimationDegree=" + mAnimationDegree +
                  "\n mSideDegree=" + mSideDegree +
                  "\n mZeroStartDegree=" + mZeroStartDegree +
                  "\n mStartDegree=" + mStartDegree +
                  "\n mEndDegree=" + mEndDegree +
                  "\n mSide=" + mSide +
                  '}';
      }
  }
  