content: /*
   * Copyright 2014 Google Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.wxy.chinamapview.util;
  
  import android.graphics.Path;
  import android.graphics.PointF;
  
  import java.text.ParseException;
  
  public class SvgPathParserUtil {
      private static final int TOKEN_ABSOLUTE_COMMAND = 1;
      private static final int TOKEN_RELATIVE_COMMAND = 2;
      private static final int TOKEN_VALUE = 3;
      private static final int TOKEN_EOF = 4;
      private int mCurrentToken;
      private PointF mCurrentPoint = new PointF();
      private int mLength;
      private int mIndex;
      private String mPathString;
      private float Max_X,Min_x,Max_y,Min_y;
      protected float transformX(float x) {
          return x;
      }
      protected float transformY(float y) {
          return y;
      }
      public Path parsePath(String s) throws ParseException {
          mCurrentPoint.set(Float.NaN, Float.NaN);
          mPathString = s;
          mIndex = 0;
          mLength = mPathString.length();
          PointF tempPoint1 = new PointF();
          PointF tempPoint2 = new PointF();
          PointF tempPoint3 = new PointF();
          Path p = new Path();
          p.setFillType(Path.FillType.WINDING);
          boolean firstMove = true;
          while (mIndex < mLength) {
              char command = consumeCommand();
              boolean relative = (mCurrentToken == TOKEN_RELATIVE_COMMAND);
              switch (command) {
                  case 'M':
                  case 'm': {
                      boolean firstPoint = true;
                      while (advanceToNextToken() == TOKEN_VALUE) {
                          consumeAndTransformPoint(tempPoint1,
                                  relative && mCurrentPoint.x != Float.NaN);
                          if (firstPoint) {
                              getMaxAndMinXY(tempPoint1);
                              p.moveTo(tempPoint1.x, tempPoint1.y);
                              firstPoint = false;
                              if (firstMove) {
                                  mCurrentPoint.set(tempPoint1);
                                  firstMove = false;
                              }
                          }
                          else {
                              getMaxAndMinXY(tempPoint1);
                              p.lineTo(tempPoint1.x, tempPoint1.y);
                          }
                      }
                      mCurrentPoint.set(tempPoint1);
                      break;
                  }
                  case 'C':
                  case 'c': {
                      if (mCurrentPoint.x == Float.NaN) {
                          throw new ParseException("Relative commands require current point", mIndex);
                      }
  
                      while (advanceToNextToken() == TOKEN_VALUE) {
                          consumeAndTransformPoint(tempPoint1, relative);
                          consumeAndTransformPoint(tempPoint2, relative);
                          consumeAndTransformPoint(tempPoint3, relative);
                          p.cubicTo(tempPoint1.x, tempPoint1.y, tempPoint2.x, tempPoint2.y,
                                  tempPoint3.x, tempPoint3.y);
                      }
                      mCurrentPoint.set(tempPoint3);
                      break;
                  }
                  case 'L':
                  case 'l': {
                      if (mCurrentPoint.x == Float.NaN) {
                          throw new ParseException("Relative commands require current point", mIndex);
                      }
  
                      while (advanceToNextToken() == TOKEN_VALUE) {
                          consumeAndTransformPoint(tempPoint1, relative);
                          getMaxAndMinXY(tempPoint1);
                          p.lineTo(tempPoint1.x, tempPoint1.y);
                      }
                      mCurrentPoint.set(tempPoint1);
                      break;
                  }
                  case 'H':
                  case 'h': {
                      if (mCurrentPoint.x == Float.NaN) {
                          throw new ParseException("Relative commands require current point", mIndex);
                      }
  
                      while (advanceToNextToken() == TOKEN_VALUE) {
                          float x = transformX(consumeValue());
                          if (relative) {
                              x += mCurrentPoint.x;
                          }
                          getMaxAndMinXY(tempPoint1);
                          p.lineTo(x, mCurrentPoint.y);
                      }
                      mCurrentPoint.set(tempPoint1);
                      break;
                  }
                  case 'V':
                  case 'v': {
                      if (mCurrentPoint.x == Float.NaN) {
                          throw new ParseException("Relative commands require current point", mIndex);
                      }
                      while (advanceToNextToken() == TOKEN_VALUE) {
                          float y = transformY(consumeValue());
                          if (relative) {
                              y += mCurrentPoint.y;
                          }
                          p.lineTo(mCurrentPoint.x, y);
                      }
                      mCurrentPoint.set(tempPoint1);
                      break;
                  }
                  case 'Z':
                  case 'z': {
                      p.close();
                      break;
                  }
              }
  
          }
  
          return p;
      }
  private void getMaxAndMinXY(PointF pointF){
      if (pointF.x>=Max_X){
          Max_X=pointF.x;
      }
      if (pointF.x<=Min_x){
          Min_x=pointF.x;
      }
      if (pointF.y>=Max_y){
          Max_y=pointF.y;
      }
      if (pointF.y<=Min_y){
          Min_y=pointF.y;
      }
  }
      private int advanceToNextToken() {
          while (mIndex < mLength) {
              char c = mPathString.charAt(mIndex);
              if ('a' <= c && c <= 'z') {
                  return (mCurrentToken = TOKEN_RELATIVE_COMMAND);
              } else if ('A' <= c && c <= 'Z') {
                  return (mCurrentToken = TOKEN_ABSOLUTE_COMMAND);
              } else if (('0' <= c && c <= '9') || c == '.' || c == '-') {
                  return (mCurrentToken = TOKEN_VALUE);
              }
  
              ++mIndex;
          }
  
          return (mCurrentToken = TOKEN_EOF);
      }
  
      private char consumeCommand() throws ParseException {
          advanceToNextToken();
          if (mCurrentToken != TOKEN_RELATIVE_COMMAND && mCurrentToken != TOKEN_ABSOLUTE_COMMAND) {
              throw new ParseException("Expected command", mIndex);
          }
  
          return mPathString.charAt(mIndex++);
      }
  
      private void consumeAndTransformPoint(PointF out, boolean relative) throws ParseException {
          out.x = transformX(consumeValue());
          out.y = transformY(consumeValue());
          if (relative) {
              out.x += mCurrentPoint.x;
              out.y += mCurrentPoint.y;
          }
      }
  
      private float consumeValue() throws ParseException {
          advanceToNextToken();
          if (mCurrentToken != TOKEN_VALUE) {
              throw new ParseException("Expected value", mIndex);
          }
  
          boolean start = true;
          boolean seenDot = false;
          int index = mIndex;
          while (index < mLength) {
              char c = mPathString.charAt(index);
              if (!('0' <= c && c <= '9') && (c != '.' || seenDot) && (c != '-' || !start)) {
                  break;
              }
              if (c == '.') {
                  seenDot = true;
              }
              start = false;
              ++index;
          }
  
          if (index == mIndex) {
              throw new ParseException("Expected value", mIndex);
          }
  
          String str = mPathString.substring(mIndex, index);
          try {
              float value = Float.parseFloat(str);
              mIndex = index;
              return value;
          } catch (NumberFormatException e) {
              throw new ParseException("Invalid float value '" + str + "'.", mIndex);
          }
      }
      public float getMax_X(){
  
          return Max_X;
      }
      public float getMax_Y(){
  
          return Max_y;
      }
      public float getMin_X(){
  
          return Min_x;
      }
      public float getMin_Y(){
  
          return Min_y;
      }
  
  }
  