1c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy/* 2c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * Copyright 2018 The Android Open Source Project 3c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 4c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * you may not use this file except in compliance with the License. 6c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * You may obtain a copy of the License at 7c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 8c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 9c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 10c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * Unless required by applicable law or agreed to in writing, software 11c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * See the License for the specific language governing permissions and 14c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * limitations under the License. 15c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy */ 16c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 17c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guypackage androidx.core.graphics; 18c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 19c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport android.graphics.Path; 20c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport android.graphics.PointF; 21c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 22c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport androidx.annotation.FloatRange; 23c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport androidx.annotation.NonNull; 24c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport androidx.annotation.RequiresApi; 25c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 26c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport java.util.ArrayList; 27c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport java.util.Collection; 28c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guyimport java.util.List; 29c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 30c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy/** A set of path-related utility methods. */ 31c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guypublic final class PathUtils { 32c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy /** 33c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * Flattens (or approximate) a {@link Path} with a series of line segments using a 0.5 pixel 34c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * error. 35c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 36c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * <em>Note:</em> This method requires API 26 or newer. 37c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 38c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * @see #flatten(Path, float) 39c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy */ 40c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy @RequiresApi(26) 41c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy @NonNull 42c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy public static Collection<PathSegment> flatten(@NonNull Path path) { 43c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy return flatten(path, 0.5f); 44c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy } 45c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 46c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy /** 47c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * Flattens (or approximate) a {@link Path} with a series of line segments. 48c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 49c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * <em>Note:</em> This method requires API 26 or newer. 50c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 51c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * @param error The acceptable error for a line on the Path. Typically this would be 52c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 0.5 so that the error is less than half a pixel. 53c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * 54c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy * @see Path#approximate 55c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy */ 56c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy @RequiresApi(26) 57c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy @NonNull 58c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy public static Collection<PathSegment> flatten(@NonNull final Path path, 59c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy @FloatRange(from = 0) final float error) { 60c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float[] pathData = path.approximate(error); 61c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy int pointCount = pathData.length / 3; 62c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy List<PathSegment> segments = new ArrayList<>(pointCount); 63c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy for (int i = 1; i < pointCount; i++) { 64c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy int index = i * 3; 65c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy int prevIndex = (i - 1) * 3; 66c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 67c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float d = pathData[index]; 68c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float x = pathData[index + 1]; 69c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float y = pathData[index + 2]; 70c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 71c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float pd = pathData[prevIndex]; 72c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float px = pathData[prevIndex + 1]; 73c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy float py = pathData[prevIndex + 2]; 74c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 75c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy if (d != pd && (x != px || y != py)) { 76c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy segments.add(new PathSegment(new PointF(px, py), pd, new PointF(x, y), d)); 77c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy } 78c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy } 79c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy return segments; 80c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy } 81c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy 82c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy private PathUtils() { 83c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy } 84c5032d73c8d389a2b62cc721bfecde2937d4a363Romain Guy} 85