1491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta/* 2491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Copyright (C) 2015 The Android Open Source Project 3491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 4491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * you may not use this file except in compliance with the License. 6491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * You may obtain a copy of the License at 7491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 8491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 9491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 10491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 11491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * See the License for the specific language governing permissions and 14491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * limitations under the License. 15491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 16491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 17491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptapackage android.util; 18491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 19491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport com.android.ide.common.rendering.api.LayoutLog; 20491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport com.android.layoutlib.bridge.Bridge; 21491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport com.android.layoutlib.bridge.impl.DelegateManager; 22491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 23491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 24491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport android.annotation.NonNull; 25491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport android.graphics.Path_Delegate; 26491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 27491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport java.util.ArrayList; 28491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport java.util.Arrays; 29491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport java.util.logging.Level; 30491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptaimport java.util.logging.Logger; 31491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 32491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta/** 33491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Delegate that provides implementation for native methods in {@link android.util.PathParser} 34491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * <p/> 35491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Through the layoutlib_create tool, selected methods of PathParser have been replaced by calls to 36491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * methods of the same name in this delegate class. 37491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 38491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Most of the code has been taken from the implementation in 39491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * {@code tools/base/sdk-common/src/main/java/com/android/ide/common/vectordrawable/PathParser.java} 40491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * revision be6fe89a3b686db5a75e7e692a148699973957f3 41491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 42491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Guptapublic class PathParser_Delegate { 43491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 44491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static final Logger LOGGER = Logger.getLogger("PathParser"); 45491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 46491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // ---- Builder delegate manager ---- 47491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static final DelegateManager<PathParser_Delegate> sManager = 48491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta new DelegateManager<PathParser_Delegate>(PathParser_Delegate.class); 49491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 50491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // ---- delegate data ---- 51491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull 52491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private PathDataNode[] mPathDataNodes; 53491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static PathParser_Delegate getDelegate(long nativePtr) { 555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return sManager.getDelegate(nativePtr); 565d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 575d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 58491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private PathParser_Delegate(@NonNull PathDataNode[] nodes) { 59491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta mPathDataNodes = nodes; 60491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 61491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 625d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public PathDataNode[] getPathDataNodes() { 635d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return mPathDataNodes; 645d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 655d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 66491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 67a0a51b6fb629c06c763b73cfe24c6c4d540d54ebDiego Perez /*package*/ static void nParseStringForPath(long pathPtr, @NonNull String pathString, int 68491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta stringLength) { 69491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta Path_Delegate path_delegate = Path_Delegate.getDelegate(pathPtr); 70491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (path_delegate == null) { 71a0a51b6fb629c06c763b73cfe24c6c4d540d54ebDiego Perez return; 72491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 73491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta assert pathString.length() == stringLength; 745d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate); 75491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 76491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 77491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 78491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static void nCreatePathFromPathData(long outPathPtr, long pathData) { 79491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta Path_Delegate path_delegate = Path_Delegate.getDelegate(outPathPtr); 80491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate source = sManager.getDelegate(outPathPtr); 81491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (source == null || path_delegate == null) { 82491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return; 83491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 845d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate); 85491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 86491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 87491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 88491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static long nCreateEmptyPathData() { 89491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate newDelegate = new PathParser_Delegate(new PathDataNode[0]); 90491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return sManager.addNewDelegate(newDelegate); 91491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 92491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 93491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 94491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static long nCreatePathData(long nativePtr) { 95491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate source = sManager.getDelegate(nativePtr); 96491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (source == null) { 97491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return 0; 98491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 99491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate dest = new PathParser_Delegate(deepCopyNodes(source.mPathDataNodes)); 100491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return sManager.addNewDelegate(dest); 101491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 102491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 103491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 104491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static long nCreatePathDataFromString(@NonNull String pathString, 105491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int stringLength) { 106491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta assert pathString.length() == stringLength : "Inconsistent path string length."; 107491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathDataNode[] nodes = createNodesFromPathData(pathString); 108491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate delegate = new PathParser_Delegate(nodes); 109491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return sManager.addNewDelegate(delegate); 110491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 111491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 112491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 113491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 114491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static boolean nInterpolatePathData(long outDataPtr, long fromDataPtr, 115491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta long toDataPtr, float fraction) { 116491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate out = sManager.getDelegate(outDataPtr); 117491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate from = sManager.getDelegate(fromDataPtr); 118491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate to = sManager.getDelegate(toDataPtr); 119491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (out == null || from == null || to == null) { 120491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return false; 121491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 122491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int length = from.mPathDataNodes.length; 123491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (length != to.mPathDataNodes.length) { 124491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_BROKEN, 125491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta "Cannot interpolate path data with different lengths (from " + length + " to " + 126491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta to.mPathDataNodes.length + ").", null); 127491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return false; 128491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 129491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (out.mPathDataNodes.length != length) { 130491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta out.mPathDataNodes = new PathDataNode[length]; 131491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 132491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (int i = 0; i < length; i++) { 1335d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (out.mPathDataNodes[i] == null) { 1345d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez out.mPathDataNodes[i] = new PathDataNode(from.mPathDataNodes[i]); 1355d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 136491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta out.mPathDataNodes[i].interpolatePathDataNode(from.mPathDataNodes[i], 1375d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez to.mPathDataNodes[i], fraction); 138491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 139491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return true; 140491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 141491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 142491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 143491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static void nFinalize(long nativePtr) { 144491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta sManager.removeJavaReferenceFor(nativePtr); 145491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 146491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 147491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 148491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static boolean nCanMorph(long fromDataPtr, long toDataPtr) { 1495d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez PathParser_Delegate fromPath = PathParser_Delegate.getDelegate(fromDataPtr); 1505d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez PathParser_Delegate toPath = PathParser_Delegate.getDelegate(toDataPtr); 1515d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (fromPath == null || toPath == null || fromPath.getPathDataNodes() == null || toPath 1525d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez .getPathDataNodes() == null) { 1535d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return true; 1545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 1555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return PathParser_Delegate.canMorph(fromPath.getPathDataNodes(), toPath.getPathDataNodes()); 156491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 157491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 158491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @LayoutlibDelegate 159491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /*package*/ static void nSetPathData(long outDataPtr, long fromDataPtr) { 160491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate out = sManager.getDelegate(outDataPtr); 161491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathParser_Delegate from = sManager.getDelegate(fromDataPtr); 162491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (from == null || out == null) { 163491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return; 164491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 165491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta out.mPathDataNodes = deepCopyNodes(from.mPathDataNodes); 166491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 167491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 168491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 169491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param pathData The string representing a path, the same as "d" string in svg file. 170491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 171491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @return an array of the PathDataNode. 172491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 173491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull 1745d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static PathDataNode[] createNodesFromPathData(@NonNull String pathData) { 175491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int start = 0; 176491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int end = 1; 177491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 178491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta ArrayList<PathDataNode> list = new ArrayList<PathDataNode>(); 179491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta while (end < pathData.length()) { 180491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta end = nextStart(pathData, end); 181491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta String s = pathData.substring(start, end).trim(); 182491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (s.length() > 0) { 183491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta float[] val = getFloats(s); 184491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta addNode(list, s.charAt(0), val); 185491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 186491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 187491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta start = end; 188491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta end++; 189491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 190491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if ((end - start) == 1 && start < pathData.length()) { 191491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta addNode(list, pathData.charAt(start), new float[0]); 192491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 193491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return list.toArray(new PathDataNode[list.size()]); 194491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 195491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 196491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 197491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param source The array of PathDataNode to be duplicated. 198491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 199491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @return a deep copy of the <code>source</code>. 200491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 201491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull 2025d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) { 203491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta PathDataNode[] copy = new PathDataNode[source.length]; 204491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (int i = 0; i < source.length; i++) { 205491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta copy[i] = new PathDataNode(source[i]); 206491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 207491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return copy; 208491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 209491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 2105d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez /** 2115d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * @param nodesFrom The source path represented in an array of PathDataNode 2125d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * @param nodesTo The target path represented in an array of PathDataNode 2135d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code> 2145d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez */ 2155d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) { 2165d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (nodesFrom == null || nodesTo == null) { 2175d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return false; 2185d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2195d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 2205d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (nodesFrom.length != nodesTo.length) { 2215d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return false; 2225d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2235d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 2245d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez for (int i = 0; i < nodesFrom.length; i ++) { 2255d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (nodesFrom[i].mType != nodesTo[i].mType 2265d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) { 2275d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return false; 2285d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2295d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2305d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez return true; 2315d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2325d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 2335d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez /** 2345d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * Update the target's data to match the source. 2355d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * Before calling this, make sure canMorph(target, source) is true. 2365d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * 2375d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * @param target The target path represented in an array of PathDataNode 2385d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * @param source The source path represented in an array of PathDataNode 2395d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez */ 2405d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static void updateNodes(PathDataNode[] target, PathDataNode[] source) { 2415d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez for (int i = 0; i < source.length; i ++) { 2425d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez target[i].mType = source[i].mType; 2435d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez for (int j = 0; j < source[i].mParams.length; j ++) { 2445d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez target[i].mParams[j] = source[i].mParams[j]; 2455d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2465d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2475d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 2485d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 249491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static int nextStart(@NonNull String s, int end) { 250491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta char c; 251491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 252491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta while (end < s.length()) { 253491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta c = s.charAt(end); 254491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // Note that 'e' or 'E' are not valid path commands, but could be 255491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // used for floating point numbers' scientific notation. 256491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // Therefore, when searching for next command, we should ignore 'e' 257491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // and 'E'. 258491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) 259491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta && c != 'e' && c != 'E') { 260491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return end; 261491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 262491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta end++; 263491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 264491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return end; 265491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 266491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 267491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 268491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Calculate the position of the next comma or space or negative sign 269491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 270491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param s the string to search 271491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param start the position to start searching 272491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param result the result of the extraction, including the position of the the starting 273491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * position of next number, whether it is ending with a '-'. 274491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 275491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static void extract(@NonNull String s, int start, @NonNull ExtractFloatResult result) { 276491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // Now looking for ' ', ',', '.' or '-' from the start. 277491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int currentIndex = start; 278491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta boolean foundSeparator = false; 279491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta result.mEndWithNegOrDot = false; 280491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta boolean secondDot = false; 281491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta boolean isExponential = false; 282491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (; currentIndex < s.length(); currentIndex++) { 283491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta boolean isPrevExponential = isExponential; 284491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta isExponential = false; 285491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta char currentChar = s.charAt(currentIndex); 286491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta switch (currentChar) { 287491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case ' ': 288491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case ',': 289491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta foundSeparator = true; 290491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 291491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case '-': 292491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // The negative sign following a 'e' or 'E' is not a separator. 293491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (currentIndex != start && !isPrevExponential) { 294491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta foundSeparator = true; 295491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta result.mEndWithNegOrDot = true; 296491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 297491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 298491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case '.': 299491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (!secondDot) { 300491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta secondDot = true; 301491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } else { 302491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // This is the second dot, and it is considered as a separator. 303491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta foundSeparator = true; 304491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta result.mEndWithNegOrDot = true; 305491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 306491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 307491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'e': 308491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'E': 309491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta isExponential = true; 310491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 311491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 312491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (foundSeparator) { 313491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 314491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 315491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 316491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // When there is nothing found, then we put the end position to the end 317491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // of the string. 318491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta result.mEndPosition = currentIndex; 319491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 320491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 321491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 322491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Parse the floats in the string. This is an optimized version of 323491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * parseFloat(s.split(",|\\s")); 324491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 325491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param s the string containing a command and list of floats 326491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 327491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @return array of floats 328491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 329491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull 330491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static float[] getFloats(@NonNull String s) { 331491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (s.charAt(0) == 'z' || s.charAt(0) == 'Z') { 332491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return new float[0]; 333491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 334491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta try { 335491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta float[] results = new float[s.length()]; 336491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int count = 0; 337491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int startPosition = 1; 338491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int endPosition; 339491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 340491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta ExtractFloatResult result = new ExtractFloatResult(); 341491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int totalLength = s.length(); 342491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 343491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // The startPosition should always be the first character of the 344491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // current number, and endPosition is the character after the current 345491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // number. 346491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta while (startPosition < totalLength) { 347491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta extract(s, startPosition, result); 348491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta endPosition = result.mEndPosition; 349491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 350491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (startPosition < endPosition) { 351491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta results[count++] = Float.parseFloat( 352491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta s.substring(startPosition, endPosition)); 353491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 354491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 355491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (result.mEndWithNegOrDot) { 356491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // Keep the '-' or '.' sign with next number. 357491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta startPosition = endPosition; 358491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } else { 359491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta startPosition = endPosition + 1; 360491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 361491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 362491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return Arrays.copyOf(results, count); 363491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } catch (NumberFormatException e) { 364d88c717b4e124e435e54bf1542774aa100773c3eDiego Perez assert false : "error in parsing \"" + s + "\"" + e; 365d88c717b4e124e435e54bf1542774aa100773c3eDiego Perez return new float[0]; 366491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 367491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 368491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 369491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 370491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static void addNode(@NonNull ArrayList<PathDataNode> list, char cmd, 371491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull float[] val) { 372491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta list.add(new PathDataNode(cmd, val)); 373491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 374491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 375491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private static class ExtractFloatResult { 376491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // We need to return the position of the next separator and whether the 377491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // next float starts with a '-' or a '.'. 378491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private int mEndPosition; 379491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private boolean mEndWithNegOrDot; 380491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 381491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 382491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 383491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Each PathDataNode represents one command in the "d" attribute of the svg file. An array of 384491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * PathDataNode can represent the whole "d" attribute. 385491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 3865d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static class PathDataNode { 387491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private char mType; 388491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull 389491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private float[] mParams; 390491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 391491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private PathDataNode(char type, @NonNull float[] params) { 392491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta mType = type; 393491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta mParams = params; 394491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 395491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 396491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta public char getType() { 397491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return mType; 398491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 399491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 400491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull 401491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta public float[] getParams() { 402491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return mParams; 403491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 404491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 405491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private PathDataNode(@NonNull PathDataNode n) { 406491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta mType = n.mType; 407491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta mParams = Arrays.copyOf(n.mParams, n.mParams.length); 408491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 409491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 410491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 4115d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * Convert an array of PathDataNode to Path. Reset the passed path as needed before 4125d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez * calling this method. 413491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 414491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param node The source array of PathDataNode. 415491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param path The target Path object. 416491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 4175d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez public static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path_Delegate path) { 418491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta float[] current = new float[6]; 419491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta char previousCommand = 'm'; 420491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta //noinspection ForLoopReplaceableByForEach 421491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (int i = 0; i < node.length; i++) { 422491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); 423491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta previousCommand = node[i].mType; 424491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 425491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 426491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 427491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 428491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * The current PathDataNode will be interpolated between the <code>nodeFrom</code> and 429491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * <code>nodeTo</code> according to the <code>fraction</code>. 430491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 431491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param nodeFrom The start value as a PathDataNode. 432491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param nodeTo The end value as a PathDataNode 433491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param fraction The fraction to interpolate. 434491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 435491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta private void interpolatePathDataNode(@NonNull PathDataNode nodeFrom, 436491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @NonNull PathDataNode nodeTo, float fraction) { 437491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (int i = 0; i < nodeFrom.mParams.length; i++) { 438491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta mParams[i] = nodeFrom.mParams[i] * (1 - fraction) 439491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + nodeTo.mParams[i] * fraction; 440491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 441491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 442491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 443491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta @SuppressWarnings("PointlessArithmeticExpression") 4445d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez private static void addCommand(@NonNull Path_Delegate path, float[] current, 4455d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez char previousCmd, char cmd, @NonNull float[] val) { 446491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 447491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int incr = 2; 4485d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float currentX = current[0]; 4495d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float currentY = current[1]; 4505d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float ctrlPointX = current[2]; 4515d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float ctrlPointY = current[3]; 4525d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float currentSegmentStartX = current[4]; 4535d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float currentSegmentStartY = current[5]; 4545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float reflectiveCtrlPointX; 4555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez float reflectiveCtrlPointY; 456491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 457491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta switch (cmd) { 458491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'z': 459491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'Z': 4605d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.close(); 4615d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez // Path is closed here, but we need to move the pen to the 4625d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez // closed position. So we cache the segment's starting position, 4635d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez // and restore it here. 4645d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = currentSegmentStartX; 4655d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = currentSegmentStartY; 4665d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentSegmentStartX; 4675d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentSegmentStartY; 4685d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.moveTo(currentX, currentY); 4695d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez break; 470491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'm': 471491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'M': 472491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'l': 473491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'L': 474491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 't': 475491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'T': 476491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta incr = 2; 477491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 478491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'h': 479491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'H': 480491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'v': 481491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'V': 482491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta incr = 1; 483491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 484491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'c': 485491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'C': 486491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta incr = 6; 487491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 488491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 's': 489491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'S': 490491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'q': 491491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'Q': 492491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta incr = 4; 493491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 494491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'a': 495491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta case 'A': 496491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta incr = 7; 4975d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez break; 498491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 499491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 500491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (int k = 0; k < val.length; k += incr) { 501491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta switch (cmd) { 5025d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'm': // moveto - Start a new sub-path (relative) 5035d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 0]; 5045d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 1]; 5055d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 506491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (k > 0) { 507491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // According to the spec, if a moveto is followed by multiple 508491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // pairs of coordinates, the subsequent pairs are treated as 509491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // implicit lineto commands. 5105d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rLineTo(val[k + 0], val[k + 1]); 511491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } else { 5125d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rMoveTo(val[k + 0], val[k + 1]); 5135d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentSegmentStartX = currentX; 5145d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentSegmentStartY = currentY; 515491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 516491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5175d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'M': // moveto - Start a new sub-path 5185d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 0]; 5195d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 1]; 5205d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 521491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (k > 0) { 522491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // According to the spec, if a moveto is followed by multiple 523491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // pairs of coordinates, the subsequent pairs are treated as 524491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // implicit lineto commands. 5255d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.lineTo(val[k + 0], val[k + 1]); 526491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } else { 5275d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.moveTo(val[k + 0], val[k + 1]); 5285d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentSegmentStartX = currentX; 5295d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentSegmentStartY = currentY; 530491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 531491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5325d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'l': // lineto - Draw a line from the current point (relative) 5335d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rLineTo(val[k + 0], val[k + 1]); 5345d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 0]; 5355d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 1]; 536491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5375d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'L': // lineto - Draw a line from the current point 5385d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.lineTo(val[k + 0], val[k + 1]); 5395d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 0]; 5405d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 1]; 541491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5425d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'h': // horizontal lineto - Draws a horizontal line (relative) 5435d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rLineTo(val[k + 0], 0); 5445d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 0]; 545491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5465d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'H': // horizontal lineto - Draws a horizontal line 5475d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.lineTo(val[k + 0], currentY); 5485d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 0]; 549491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5505d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'v': // vertical lineto - Draws a vertical line from the current point (r) 5515d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rLineTo(0, val[k + 0]); 5525d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 0]; 553491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'V': // vertical lineto - Draws a vertical line from the current point 5555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.lineTo(currentX, val[k + 0]); 5565d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 0]; 557491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5585d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'c': // curveto - Draws a cubic Bézier curve (relative) 5595d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 5605d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 4], val[k + 5]); 5615d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 5625d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentX + val[k + 2]; 5635d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentY + val[k + 3]; 5645d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 4]; 5655d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 5]; 5665d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 567491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5685d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'C': // curveto - Draws a cubic Bézier curve 5695d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 570491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta val[k + 4], val[k + 5]); 5715d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 4]; 5725d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 5]; 5735d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = val[k + 2]; 5745d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = val[k + 3]; 575491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5765d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) 5775d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = 0; 5785d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = 0; 5795d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (previousCmd == 'c' || previousCmd == 's' 5805d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez || previousCmd == 'C' || previousCmd == 'S') { 5815d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = currentX - ctrlPointX; 5825d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = currentY - ctrlPointY; 5835d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 5845d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 5855d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 0], val[k + 1], 5865d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 2], val[k + 3]); 5875d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez 5885d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentX + val[k + 0]; 5895d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentY + val[k + 1]; 5905d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 2]; 5915d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 3]; 592491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 5935d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) 5945d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = currentX; 5955d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = currentY; 5965d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (previousCmd == 'c' || previousCmd == 's' 5975d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez || previousCmd == 'C' || previousCmd == 'S') { 5985d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 5995d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 6005d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 6015d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 6025d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 6035d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = val[k + 0]; 6045d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = val[k + 1]; 6055d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 2]; 6065d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 3]; 607491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 6085d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'q': // Draws a quadratic Bézier (relative) 6095d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 6105d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentX + val[k + 0]; 6115d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentY + val[k + 1]; 6125d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 2]; 6135d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 3]; 614491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 6155d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'Q': // Draws a quadratic Bézier 616491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 6175d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = val[k + 0]; 6185d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = val[k + 1]; 6195d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 2]; 6205d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 3]; 621491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 6225d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) 6235d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = 0; 6245d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = 0; 6255d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (previousCmd == 'q' || previousCmd == 't' 6265d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez || previousCmd == 'Q' || previousCmd == 'T') { 6275d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = currentX - ctrlPointX; 6285d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = currentY - ctrlPointY; 6295d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 6305d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 6315d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 0], val[k + 1]); 6325d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentX + reflectiveCtrlPointX; 6335d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentY + reflectiveCtrlPointY; 6345d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 0]; 6355d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 1]; 636491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 6375d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'T': // Draws a quadratic Bézier curve (reflective control point) 6385d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = currentX; 6395d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = currentY; 6405d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez if (previousCmd == 'q' || previousCmd == 't' 6415d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez || previousCmd == 'Q' || previousCmd == 'T') { 6425d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 6435d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 6445d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez } 6455d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 6465d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 0], val[k + 1]); 6475d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = reflectiveCtrlPointX; 6485d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = reflectiveCtrlPointY; 6495d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 0]; 6505d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 1]; 651491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 6525d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'a': // Draws an elliptical arc 653491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 6545d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez drawArc(path, 6555d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX, 6565d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY, 6575d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 5] + currentX, 6585d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 6] + currentY, 6595d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 0], 6605d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 1], 6615d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 2], 6625d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 3] != 0, 663491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta val[k + 4] != 0); 6645d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX += val[k + 5]; 6655d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY += val[k + 6]; 6665d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentX; 6675d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentY; 668491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 6695d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez case 'A': // Draws an elliptical arc 6705d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez drawArc(path, 6715d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX, 6725d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY, 6735d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 5], 6745d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 6], 6755d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 0], 6765d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 1], 6775d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 2], 6785d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez val[k + 3] != 0, 679491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta val[k + 4] != 0); 6805d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentX = val[k + 5]; 6815d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez currentY = val[k + 6]; 6825d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointX = currentX; 6835d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez ctrlPointY = currentY; 684491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta break; 685491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 6865d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez previousCmd = cmd; 687491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 6885d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez current[0] = currentX; 6895d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez current[1] = currentY; 6905d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez current[2] = ctrlPointX; 6915d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez current[3] = ctrlPointY; 6925d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez current[4] = currentSegmentStartX; 6935d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez current[5] = currentSegmentStartY; 694491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 695491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 6965d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez private static void drawArc(@NonNull Path_Delegate p, float x0, float y0, float x1, 697491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta float y1, float a, float b, float theta, boolean isMoreThanHalf, 698491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta boolean isPositiveArc) { 699491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 700491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log(Level.FINE, "(" + x0 + "," + y0 + ")-(" + x1 + "," + y1 701491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + ") {" + a + " " + b + "}"); 702491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /* Convert rotation angle from degrees to radians */ 703491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double thetaD = theta * Math.PI / 180.0f; 704491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /* Pre-compute rotation matrix entries */ 705491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double cosTheta = Math.cos(thetaD); 706491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sinTheta = Math.sin(thetaD); 707491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /* Transform (x0, y0) and (x1, y1) into unit space */ 708491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /* using (inverse) rotation, followed by (inverse) scale */ 709491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double x0p = (x0 * cosTheta + y0 * sinTheta) / a; 710491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; 711491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double x1p = (x1 * cosTheta + y1 * sinTheta) / a; 712491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; 713491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log(Level.FINE, "unit space (" + x0p + "," + y0p + ")-(" + x1p 714491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + "," + y1p + ")"); 715491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /* Compute differences and averages */ 716491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double dx = x0p - x1p; 717491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double dy = y0p - y1p; 718491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double xm = (x0p + x1p) / 2; 719491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double ym = (y0p + y1p) / 2; 720491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /* Solve for intersecting unit circles */ 721491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double dsq = dx * dx + dy * dy; 722491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (dsq == 0.0) { 723491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log(Level.FINE, " Points are coincident"); 724491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return; /* Points are coincident */ 725491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 726491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double disc = 1.0 / dsq - 1.0 / 4.0; 727491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (disc < 0.0) { 728491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log(Level.FINE, "Points are too far apart " + dsq); 729491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta float adjust = (float) (Math.sqrt(dsq) / 1.99999); 730491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, 731491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta isMoreThanHalf, isPositiveArc); 732491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta return; /* Points are too far apart */ 733491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 734491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double s = Math.sqrt(disc); 735491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sdx = s * dx; 736491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sdy = s * dy; 737491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double cx; 738491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double cy; 739491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (isMoreThanHalf == isPositiveArc) { 740491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cx = xm - sdy; 741491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cy = ym + sdx; 742491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } else { 743491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cx = xm + sdy; 744491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cy = ym - sdx; 745491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 746491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 747491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double eta0 = Math.atan2((y0p - cy), (x0p - cx)); 748491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log(Level.FINE, "eta0 = Math.atan2( " + (y0p - cy) + " , " 749491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + (x0p - cx) + ") = " + Math.toDegrees(eta0)); 750491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 751491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double eta1 = Math.atan2((y1p - cy), (x1p - cx)); 752491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log(Level.FINE, "eta1 = Math.atan2( " + (y1p - cy) + " , " 753491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + (x1p - cx) + ") = " + Math.toDegrees(eta1)); 754491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sweep = (eta1 - eta0); 755491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (isPositiveArc != (sweep >= 0)) { 756491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta if (sweep > 0) { 757491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta sweep -= 2 * Math.PI; 758491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } else { 759491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta sweep += 2 * Math.PI; 760491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 761491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 762491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 763491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cx *= a; 764491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cy *= b; 765491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double tcx = cx; 766491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cx = cx * cosTheta - cy * sinTheta; 767491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta cy = tcx * sinTheta + cy * cosTheta; 768491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta LOGGER.log( 769491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta Level.FINE, 770491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta "cx, cy, a, b, x0, y0, thetaD, eta0, sweep = " + cx + " , " 771491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + cy + " , " + a + " , " + b + " , " + x0 + " , " + y0 772491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + " , " + Math.toDegrees(thetaD) + " , " 773491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + Math.toDegrees(eta0) + " , " + Math.toDegrees(sweep)); 774491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 775491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); 776491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 777491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 778491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta /** 779491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * Converts an arc to cubic Bezier segments and records them in p. 780491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * 781491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param p The target for the cubic Bezier segments 782491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param cx The x coordinate center of the ellipse 783491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param cy The y coordinate center of the ellipse 784491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param a The radius of the ellipse in the horizontal direction 785491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param b The radius of the ellipse in the vertical direction 786491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param e1x E(eta1) x coordinate of the starting point of the arc 787491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param e1y E(eta2) y coordinate of the starting point of the arc 788491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param theta The angle that the ellipse bounding rectangle makes with the horizontal 789491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * plane 790491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param start The start angle of the arc on the ellipse 791491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse 792491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta */ 7935d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez private static void arcToBezier(@NonNull Path_Delegate p, double cx, double cy, double a, 794491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double b, double e1x, double e1y, double theta, double start, 795491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sweep) { 796491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // Taken from equations at: 797491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // http://spaceroots.org/documents/ellipse/node8.html 798491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // and http://www.spaceroots.org/documents/ellipse/node22.html 799491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta // Maximum of 45 degrees per cubic Bezier segment 800491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta int numSegments = (int) Math.ceil(Math.abs(sweep * 4 / Math.PI)); 801491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 802491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 803491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double eta1 = start; 804491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double cosTheta = Math.cos(theta); 805491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sinTheta = Math.sin(theta); 806491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double cosEta1 = Math.cos(eta1); 807491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sinEta1 = Math.sin(eta1); 808491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); 809491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); 810491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 811491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double anglePerSegment = sweep / numSegments; 812491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta for (int i = 0; i < numSegments; i++) { 813491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double eta2 = eta1 + anglePerSegment; 814491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double sinEta2 = Math.sin(eta2); 815491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double cosEta2 = Math.cos(eta2); 816491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double e2x = cx + (a * cosTheta * cosEta2) 817491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta - (b * sinTheta * sinEta2); 818491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double e2y = cy + (a * sinTheta * cosEta2) 819491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta + (b * cosTheta * sinEta2); 820491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; 821491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; 822491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double tanDiff2 = Math.tan((eta2 - eta1) / 2); 823491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double alpha = Math.sin(eta2 - eta1) 824491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; 825491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double q1x = e1x + alpha * ep1x; 826491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double q1y = e1y + alpha * ep1y; 827491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double q2x = e2x - alpha * ep2x; 828491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta double q2y = e2y - alpha * ep2y; 829491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta 8305d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez p.cubicTo((float) q1x, 8315d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez (float) q1y, 8325d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez (float) q2x, 8335d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez (float) q2y, 8345d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez (float) e2x, 8355d1013cf13e59b7f8dc8f16b5811cb29982e0ef3Diego Perez (float) e2y); 836491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta eta1 = eta2; 837491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta e1x = e2x; 838491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta e1y = e2y; 839491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta ep1x = ep2x; 840491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta ep1y = ep2y; 841491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 842491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 843491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta } 844491523d52cd8368ef9a92e95fb3e9332bf86a996Deepanshu Gupta} 845